/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 Copyright (C) Picosoft s.r.l. 1995-2002

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
# include "isam.h"
# include "picoisam.h"
static char rcsid[] = "$Id: picoIsam.c,v 1.19 2002/05/06 11:25:31 picoSoft Exp $";
static char rcsidh1[] = isam_h;
static char rcsidh2[] = picoisam_h;
# include <fcntl.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <signal.h>
# include <sys/stat.h>
# include <time.h>
# include <ctype.h>
# if defined(MSDOS) || defined(WIN32)
# include <io.h>
# include <sys/locking.h>
# include "wlockmgr.h"
# define fcntl(a,b,c) win_fcntl_lk(a,b,c)
# define getuid() 0
# if !defined(WIN32)
# include <windows.h>
# define open(a,b,c) _lopen(a, READ_WRITE|OF_SHARE_COMPAT)
# define lseek       _llseek
# define read        _lread
# define write       _lwrite
# define close       _lclose
# endif
# else
# include <unistd.h>
# endif
# include <errno.h>

# define INDEX_EXT ".idx"
# define DATA_EXT  ".dat"

/*
 * limits
 */

# ifdef _NFILE
# define MAXOPENFILE (_NFILE/2)
# else
# define MAXOPENFILE 127
# endif
# define FIRSTKEYDISP 32
const int HEADERKEYSIZE =(sizeof(UINT2)*3*NPARTS+sizeof(UINT2)*3+sizeof(UINT4));
# define NKEYINCREMENT 2
# define MAXNODESIZE 2048
# define HEADERSIZE 2048

/*
 * Header
 */
# define SIGN "picoIs"
/*
 * Rel 1 = chiavi duplicate in ordine d'inserimento
 */                                                          
# define RELEASE (unsigned short)1

typedef void * Void;
typedef int FILEDESC;
typedef UINT4 ADDR;
typedef INT4 RECNUM;
typedef UINT4 PROG;
# define MAXRECNUM ((RECNUM)0x7FFFFFFF)
typedef int ISBOOL;
# define ISTRUE (1==1)
# define ISFALSE (1==0)

typedef struct tNodeItemDesc {
   unsigned char keyVal[MAXKEYSIZE + sizeof(RECNUM)];
   RECNUM numRec;
   short keyPos;
   ADDR nodeAddr;
   PROG keyProg;
} NodeItemDesc;
# define setNodeItemDesc(t,k,nr,kps,na,kpg,klen) \
   if (k != 0) memcpy(t.keyVal,k,klen); \
   else        memset(t.keyVal, 0, MAXKEYSIZE); \
   t.numRec = nr; \
   t.keyPos = kps; \
   t.nodeAddr = na; \
   t.keyProg = kpg


typedef struct tNewNodes {
   unsigned char keyValMin[MAXKEYSIZE + sizeof(PROG)];
   ADDR nodeAddrKMin;
   unsigned char keyValMax[MAXKEYSIZE + sizeof(PROG)];
   ADDR nodeAddrKMax;
} NewNodes;

struct keysup {
   unsigned char bufKey[MAXKEYSIZE + sizeof(PROG)];
};

typedef struct tRecordLock {
   FILEDESC isfd;
   RECNUM numRec;
   struct tRecordLock *next;
} RecordLock;

typedef struct tSharedFile {
   char *name;
   int fd;
   int mode;
   int cnt;
   RecordLock *lckChain;
} SharedFile;

typedef struct tFileDesc {
   char * indexName;
   char * dataName;
   int fdIndex;
   int fdData;
   ADDR firstFreeNode;
   struct dictinfo dictInfo;
   struct keydesc ** keyDesc;
   struct keysup ** keySup;
   int keyVecSize;
   int openMode;
   unsigned char * node;
   unsigned char * record;
   unsigned char * delrecnode;
   short headerSize;
   ADDR firstAddKeyNode;
   ADDR firstDeletedNode;
   ADDR firstDelRecNode;

   short currIndex;     /* 0 - 7, -1 = lettura fisica */
   NodeItemDesc curr;
   NodeItemDesc next;

   enum _pI__lckType {
       ISNOLCK,
       ISRDLCK,
       ISWRLCK
   } headerLock;
   int fileLock;
   RECNUM lastRecordLock;
   SharedFile *dataShFile;
   SharedFile *indxShFile;
   short releaseLevel;
#ifdef AUDIT_TRAIL
   char *auditName;
   int auditFd;
#endif
} FileDesc;

/*
 * Node type
 */

# define BRANCH_NODE (unsigned char)0xBF
# define LEAF_NODE (unsigned char)0xFF
# define DELETED_NODE (unsigned char)0xDF
# define RECDEL_NODE (unsigned char)0xEF
# define KEY_NODE (unsigned char)0xCF

# define PAST_END 0xFFFFFFFFL


typedef struct tNodeDesc {
   unsigned char nodeType;
   short numElem;
   ADDR leftBrot;
   ADDR rightBrot;

   ADDR  nodeAddr;
   short usableSize;
   struct keydesc *kdesc;
   short maxElem;
   unsigned char * nodeArea;
} NodeDesc;
/*
 * Global variables
 */

static FileDesc *Files[MAXOPENFILE];
static unsigned char * headerArea = 0;
static short maxHeaderArea = 0;
static void (*origSigInt)(int) = SIG_DFL;
static void (*origSigQuit)(int) = SIG_DFL;
static void (*origSigTerm)(int) = SIG_DFL;
int pIserrno;
int pIserrio;
UINT4 pIsrecnum;

/*
 * Macro
 */
# define RETURN    { if (isfd >= 0 && Files[isfd] && \
                                      Files[isfd]->headerLock != ISNOLCK) \
                       _pI__headerUnlock(isfd); \
                    return Return; }
# define FILEDESC_ERROR -1
# define isKeyDup(isfd,keynum) \
      ((Files[isfd]->keyDesc[keynum]->k_flags & 0x01) == ISDUPS)

# define getWaitMode(m) (m&0xF000)
# define getLockMode(m) (m&0x0F00)
# define getOpenMode(m) (m&(ISINPUT|ISOUTPUT|ISINOUT))
# define getReadMode(m) (m&0x00FF)

#ifdef TRANSACTION
#include "picolog.h"
# define isOpenTrans(m) (m&ISTRANS)
static ISBOOL beginWork = ISFALSE;
static FILEDESC fileToClose[MAXOPENFILE];
static int nFileToClose = 0;
#endif

# define checkMode(m) switch (getLockMode(m)) {\
                      case ISAUTOLOCK:\
                      case ISMANULOCK:\
                      case ISEXCLLOCK:\
                         break;\
                      default:\
                         pIserrno = EBADARG;\
                         return FILEDESC_ERROR;\
                      }\
                      switch (getOpenMode(m)) {\
                      case ISINPUT:\
                      case ISOUTPUT:\
                      case ISINOUT:\
                         break;\
                      default:\
                         pIserrno = EBADARG;\
                         return FILEDESC_ERROR;\
                      }

# define checkKeyDesc(k) switch (k->k_flags & 0x01) {\
                      case ISNODUPS:\
                      case ISDUPS:\
                         break;\
                      default:\
                         pIserrno = EBADKEY;\
                         return FILEDESC_ERROR;\
                      }\
                      if (k->k_nparts < 0 || k->k_nparts > NPARTS) {\
                         pIserrno = EBADKEY;\
                         return FILEDESC_ERROR;\
                      }\
                      for (i = 0; i < k->k_nparts; i++)\
                         if ((k->k_part[i].kp_type & ~ISDESC) >= MAXTYPE) {\
                            pIserrno = EBADKEY;\
                            return FILEDESC_ERROR;\
             } /* seguono altri controlli */

# define checkKeyPart(k,reclen)  \
      switch (k.kp_type & 0x0F) {   \
      default:                      \
     pIserrno = EBADKEY;         \
     break;                     \
      case CHARTYPE:                \
         break;                     \
      case INTTYPE:                 \
     k.kp_leng = sizeof (INT2); \
         break;                     \
      case LONGTYPE:                \
     k.kp_leng = sizeof (INT4); \
         break;                     \
      case DOUBLETYPE:              \
     k.kp_leng = sizeof (double); \
         break;                     \
      case FLOATTYPE:               \
     k.kp_leng = sizeof (float);\
         break;                     \
      }                             \
      if (k.kp_start < 0 || k.kp_leng  < 0 || \
      k.kp_start + k.kp_leng  > reclen || \
      (k.kp_type & ~ISDESC) >= MAXTYPE || \
      (k.kp_type & ~ISDESC) < 0) \
     pIserrno = EBADKEY

# define checkFileName(f) if ((i = strlen (_pI__baseName(f))) == 0) {\
                             pIserrno = EBADARG;\
                             return FILEDESC_ERROR;\
                          }
# define checkIsOpen(f) if (f < 0 || f >= MAXOPENFILE || Files[f] == 0) {\
                            pIserrno = ENOTOPEN;\
                            return Return;\
                        }
# define indexLseek(isfd,d)   if (lseek (Files[isfd]->fdIndex, d, 0L) < 0) { \
                                  pIserrno = errno; pIserrio = errno;\
                                  RETURN }

# define dataLseek(isfd,d)    if (lseek (Files[isfd]->fdData, \
                             (d - 1) * (Files[isfd]->dictInfo.di_recsize + 1),\
                                    0L) < 0) { \
                                  pIserrno = errno; pIserrio = errno;\
                                  RETURN }

# define writeIndex(isfd,s) \
    if (write(Files[isfd]->fdIndex, s, Files[isfd]->dictInfo.di_idxsize) < \
           Files[isfd]->dictInfo.di_idxsize) { \
                pIserrno = errno; pIserrio = errno;\
                RETURN }

# define readIndex(isfd,s) \
    if (read(Files[isfd]->fdIndex, s, Files[isfd]->dictInfo.di_idxsize) < \
           Files[isfd]->dictInfo.di_idxsize) { \
                pIserrno = errno; pIserrio = errno;\
                RETURN }

# define writeData(isfd,s) \
    if (write(Files[isfd]->fdData, s, Files[isfd]->dictInfo.di_recsize) < \
           Files[isfd]->dictInfo.di_recsize) { \
                pIserrno = errno; pIserrio = errno;\
                RETURN } \
    else if (write(Files[isfd]->fdData, "\n", 1) < 1) {\
                pIserrno = errno; pIserrio = errno;\
                RETURN }

# if defined(AUDIT_TRAIL) || defined(TRANSACTION)
# define deleteData(isfd) \
    Files[isfd]->record[Files[isfd]->dictInfo.di_recsize] = 0; \
    if (write(Files[isfd]->fdData, Files[isfd]->record, \
           Files[isfd]->dictInfo.di_recsize + 1) < \
           Files[isfd]->dictInfo.di_recsize + 1) { \
                pIserrno = errno; pIserrio = errno;\
                RETURN }
#else
# define deleteData(isfd) \
    memset (Files[isfd]->record, 0, Files[isfd]->dictInfo.di_recsize + 1); \
    if (write(Files[isfd]->fdData, Files[isfd]->record, \
           Files[isfd]->dictInfo.di_recsize + 1) < \
           Files[isfd]->dictInfo.di_recsize + 1) { \
                pIserrno = errno; pIserrio = errno;\
                RETURN }
#endif

# define unlockData(isfd,mode,recnum) \
    if (getLockMode(Files[isfd]->openMode) == ISAUTOLOCK || \
          getLockMode(mode) == ISLOCK) { \
       _pI__recordUnlock (isfd, recnum); \
       if (pIserrno != 0) \
          RETURN; \
    }

# define lockData(isfd,mode,recnum) \
    if (getLockMode(Files[isfd]->openMode) == ISAUTOLOCK || \
          getLockMode(mode) == ISLOCK) { \
       if (getLockMode(Files[isfd]->openMode) == ISAUTOLOCK) \
          _pI__allRecordUnlock (isfd); \
       _pI__recordLock (isfd, recnum, ISFALSE); \
       if (pIserrno != 0) { \
          pIsrecnum = recnum; \
          RETURN; \
       } \
    } \
    dataLseek(isfd,recnum)

# ifdef WIN32
# define readData(isfd,s,can) \
    if (read(Files[isfd]->fdData, s, Files[isfd]->dictInfo.di_recsize) < \
           Files[isfd]->dictInfo.di_recsize) { \
                pIserrno = errno; pIserrio = errno;\
                 RETURN } \
    else if (read(Files[isfd]->fdData, &can, 1) < 1) {\
       if (errno == EACCES) \
          can = '\n'; \
       else { \
          pIserrno = pIserrio = errno;\
          RETURN \
       } \
    }
# else
# define readData(isfd,s,can) \
    if (read(Files[isfd]->fdData, s, Files[isfd]->dictInfo.di_recsize) < \
           Files[isfd]->dictInfo.di_recsize) { \
                pIserrno = errno; pIserrio = errno;\
                 RETURN } \
    else if (read(Files[isfd]->fdData, &can, 1) < 1) {\
                pIserrno = errno; pIserrio = errno;\
                 RETURN }
# endif

# define checkBadFile(can) if (can != '\n') { \
                pIserrno = EBADFILE; pIserrio = errno;\
                 RETURN }

# define putLongInBuffer(cp,l)  htonlp(cp, l),cp+=sizeof(UINT4)
# define putShortInBuffer(cp,s) htonsp(cp, s),cp+=sizeof(UINT2)
# define getLongFromBuffer(l,cp) l=pntohl(cp),cp+=sizeof(UINT4)
# define getShortFromBuffer(s,cp) s=pntohs(cp),cp+=sizeof(UINT2)

# define getNumRec(node,i) \
         pntohl(&node.nodeArea[i*(node.kdesc->k_len+sizeof(UINT4)) + node.kdesc->k_len])

# define copyStruct(a,b) a = b

# define getKeyDesc(found,i, node) \
   setNodeItemDesc (found, &node->nodeArea[i*tksz], \
   pntohl(&node->nodeArea[i*tksz+node->kdesc->k_len+psz]), \
          i,node->nodeAddr, \
          pntohl(&node->nodeArea[i*tksz+node->kdesc->k_len]),\
          node->kdesc->k_len); \
   Return = &found

/* Endian functions */

typedef enum _pI__tag_endianType {
   _pI__UNDEF_ENDIAN,
   _pI__BIG_ENDIAN,
   _pI__LITTLE_ENDIAN
} _pI__endianType;

static _pI__endianType _pI__Endian = _pI__UNDEF_ENDIAN;

static void
_pI__checkEndian (void)
{
   INT4  num = 0x31323334L;

   if ( ((((char *)&num)[0]) == 0x31) && ((((char *)&num)[1]) == 0x32) &&
    ((((char *)&num)[2]) == 0x33) && ((((char *)&num)[3]) == 0x34) )
      _pI__Endian = _pI__BIG_ENDIAN;
   else if ( ((((char *)&num)[3]) == 0x31) && ((((char *)&num)[2]) == 0x32) &&
         ((((char *)&num)[1]) == 0x33) && ((((char *)&num)[0]) == 0x34) )
      _pI__Endian = _pI__LITTLE_ENDIAN; 
}

static union _pI__tagSwap {
   UINT2 num2;
   UINT4 num4;
   UCHAR chr[4];
} _pI__Swap;

static UINT2
pntohs (UCHAR * x)
{
start:
   switch (_pI__Endian) {
   case _pI__BIG_ENDIAN:
      _pI__Swap.chr[0] = x[0];
      _pI__Swap.chr[1] = x[1];
      return _pI__Swap.num2;
   case _pI__LITTLE_ENDIAN:
      _pI__Swap.chr[0] = x[1];
      _pI__Swap.chr[1] = x[0];
      return _pI__Swap.num2;
   default:
      _pI__checkEndian();
      goto start;
   }
}

static void
htonsp (UCHAR *d, UINT2 x)
{
start:
   switch (_pI__Endian) {
   case _pI__BIG_ENDIAN:
      _pI__Swap.num2 = x;
      d[0] = _pI__Swap.chr[0];
      d[1] = _pI__Swap.chr[1];
      break;
   case _pI__LITTLE_ENDIAN:
      _pI__Swap.num2 = x;
      d[0] = _pI__Swap.chr[1];
      d[1] = _pI__Swap.chr[0];
      break;
   default:
      _pI__checkEndian();
      goto start;
   }
} 

static UINT4
pntohl (UCHAR * x)
{
start:
   switch (_pI__Endian) {
   case _pI__BIG_ENDIAN:
      _pI__Swap.chr[0] = x[0];
      _pI__Swap.chr[1] = x[1];
      _pI__Swap.chr[2] = x[2];
      _pI__Swap.chr[3] = x[3];
      return _pI__Swap.num4;
   case _pI__LITTLE_ENDIAN:
      _pI__Swap.chr[0] = x[3];
      _pI__Swap.chr[1] = x[2];
      _pI__Swap.chr[2] = x[1];
      _pI__Swap.chr[3] = x[0];
      return _pI__Swap.num4;
   default:
      _pI__checkEndian();
      goto start;
   }
}

static void
htonlp (UCHAR *d, UINT4 x)
{
start:
   switch (_pI__Endian) {
   case _pI__BIG_ENDIAN:
      _pI__Swap.num4 = x;
      d[0] = _pI__Swap.chr[0];
      d[1] = _pI__Swap.chr[1];
      d[2] = _pI__Swap.chr[2];
      d[3] = _pI__Swap.chr[3];
      break;
   case _pI__LITTLE_ENDIAN:
      _pI__Swap.num4 = x;
      d[0] = _pI__Swap.chr[3];
      d[1] = _pI__Swap.chr[2];
      d[2] = _pI__Swap.chr[1];
      d[3] = _pI__Swap.chr[0];
      break;
   default:
      _pI__checkEndian();
      goto start;
   }
}

/* */

# define samePath(a,b) (strcmp(a,b) == 0)

static SharedFile *sharedFiles[MAXOPENFILE];
static int maxSharedFile = 0;

static int
_pI__sharedOpen (char *fileName, int mode, int perm, SharedFile **shfile)
{
   int Return = -1;
   register int i;
   for (i = 0; i < maxSharedFile; i++) {
      if (sharedFiles[i] != 0 && samePath (fileName, sharedFiles[i]->name)) {
         Return = sharedFiles[i]->fd;
         lseek (Return, 0L, 0);
         sharedFiles[i]->cnt++;
         *shfile = sharedFiles[i];
         return Return;
      }
   }
   Return = open (fileName, mode, perm);
   if (Return >= 0) {
      for (i = 0; i < maxSharedFile; i++)
         if (sharedFiles[i] == 0)
            break;
      sharedFiles[i] = (SharedFile *) malloc (sizeof(SharedFile));
      sharedFiles[i]->name = strdup (fileName);
      sharedFiles[i]->fd = Return;
      sharedFiles[i]->mode = mode;
      sharedFiles[i]->cnt = 1;
      sharedFiles[i]->lckChain = 0;
      *shfile = sharedFiles[i];
      if (i >= maxSharedFile)
         maxSharedFile = i + 1;
   }
   return Return;
}

static Void
_pI__recordUnlockIsfd (FILEDESC isfd, RECNUM recnum, SharedFile *shfile)
{
   Void Return = 0;

   ISBOOL locked = ISFALSE;
   RecordLock *irl = shfile->lckChain;
   RecordLock *iprl = 0;
   RecordLock *rl = 0, *prl = 0;
   for ( ; irl; iprl = irl, irl = irl->next) {
      if (irl->numRec == recnum) {
         if (irl->isfd == isfd) {
            prl = iprl;
            rl = irl;
         } else
            locked = ISTRUE;
      }
   }
   if (!locked) {
      struct flock lck;
      lck.l_whence = 0;
      lck.l_start = (recnum - 1) * (Files[isfd]->dictInfo.di_recsize + 1);
      lck.l_len = Files[isfd]->dictInfo.di_recsize + 1;
      lck.l_type = F_UNLCK;
      if (fcntl(Files[isfd]->fdData, F_SETLK, &lck) == -1) {
         pIserrio = errno;
      }
   }
   if (pIserrno == 0) {
      if (prl == 0)
         shfile->lckChain = rl->next;
      else
         prl->next = rl->next;
      free (rl);
   }
   return Return;
}

static int
_pI__sharedClose (int fd, FILEDESC isfd)
{
   int Return = -1;
   register int i;

   for (i = 0; i < maxSharedFile; i++) {
      if (sharedFiles[i] != 0 && sharedFiles[i]->fd == fd) {
         if (Files[isfd]->fileLock == 0) {
            RecordLock *rl = sharedFiles[i]->lckChain;
            RECNUM curRec;
            while (rl && pIserrno == 0) {
               if (rl->isfd == isfd) {
                  curRec = rl->numRec;
                  rl = rl->next;
                  _pI__recordUnlockIsfd (isfd, curRec, sharedFiles[i]);
               }
            }
         }
         if (--sharedFiles[i]->cnt == 0) {
            Return = close (fd);
            free (sharedFiles[i]->name);
            free (sharedFiles[i]);
            sharedFiles[i] = 0;
         } else
            Return = 0;
         break;
      }
   }
   return Return;
}

/* */

static char *
_pI__baseName (char * name)
{
   register int i;

   for (i = strlen(name); i >= 0; i--)
      if (name[i] == '/')
         break;
   return &name[i + 1];
}

static int
_pI__mapOpenMode(int m)
{
   int Return;

   switch (getOpenMode(m)) {
   case ISINPUT:
      Return = O_RDONLY;
      break;
   case ISOUTPUT:
      Return = O_RDWR;
      break;
   default:
      Return = O_RDWR;
      break;
   }
# if defined(MSDOS) || defined(WIN32)
   Return |= O_BINARY;
# endif
   return Return;
}

static void
_pI__allocKey (FILEDESC fd, short nkstart, short nkend)
{
   register short i;
   if (Files[fd]->keyVecSize < nkend) {
      int newSize = Files[fd]->keyVecSize + NKEYINCREMENT > nkend ?
                    Files[fd]->keyVecSize + NKEYINCREMENT : nkend;
      void **pnt = (void **) malloc (sizeof(struct keydesc *) * newSize);
      for (i = 0; i < Files[fd]->keyVecSize; i++)
         ((struct keydesc **)pnt)[i] = Files[fd]->keyDesc[i];
      if (Files[fd]->keyDesc)
         free (Files[fd]->keyDesc);
      Files[fd]->keyDesc = (struct keydesc **) pnt;
      pnt = (void **) malloc (sizeof(struct keysup *) * newSize);
      for (i = 0; i < Files[fd]->keyVecSize; i++)
         ((struct keysup **)pnt)[i] = Files[fd]->keySup[i];
      if (Files[fd]->keySup)
         free (Files[fd]->keySup);
      Files[fd]->keySup = (struct keysup **) pnt;
      Files[fd]->keyVecSize = newSize;
   }

   for (i = nkstart; i < nkend; i++) {
      Files[fd]->keyDesc[i] =  malloc (sizeof(struct keydesc));
      Files[fd]->keySup[i] = malloc (sizeof(struct keysup));
   }
}

static void
_pI__allocFile (FILEDESC fd, char *filename)
{
   Files[fd]->node = malloc (Files[fd]->dictInfo.di_idxsize);
   memset (Files[fd]->node, 0, Files[fd]->dictInfo.di_idxsize);

   Files[fd]->record = malloc (Files[fd]->dictInfo.di_recsize + 1);
   memset (Files[fd]->record, 0, Files[fd]->dictInfo.di_recsize + 1);

   Files[fd]->delrecnode = malloc (Files[fd]->dictInfo.di_idxsize);
   memset (Files[fd]->delrecnode, 0, Files[fd]->dictInfo.di_idxsize);

   Files[fd]->keyDesc = 0;
   Files[fd]->keySup = 0;
   Files[fd]->keyVecSize = 0;
   _pI__allocKey (fd,0,Files[fd]->dictInfo.di_nkeys);

   if (maxHeaderArea < Files[fd]->headerSize) {
      if (maxHeaderArea != 0)
         free (headerArea);
      headerArea = malloc(Files[fd]->headerSize);
      maxHeaderArea = Files[fd]->headerSize;
   }
#ifdef AUDIT_TRAIL
   Files[fd]->auditName = 0;
   Files[fd]->auditFd = -1;
#endif
}

static void _pI__headerUnlock (FILEDESC isfd);

static void
_pI__freeFile (FILEDESC fd)
{
   register short i;

   if (Files[fd] == 0)
      return;

   if (Files[fd]->headerLock != ISNOLCK)
      _pI__headerUnlock(fd);

   if (Files[fd]->fdIndex >= 0)
      _pI__sharedClose (Files[fd]->fdIndex, fd);
   if (Files[fd]->fdData >= 0)
      _pI__sharedClose (Files[fd]->fdData, fd);

   free (Files[fd]->indexName);
   free (Files[fd]->dataName);

   if (Files[fd]->node != 0) {
      free (Files[fd]->node);
      free (Files[fd]->record);
      free (Files[fd]->delrecnode);
      for (i=0;i < Files[fd]->dictInfo.di_nkeys; i++) {
         free (Files[fd]->keyDesc[i]);
         free (Files[fd]->keySup[i]);
      }
      free (Files[fd]->keyDesc);
      free (Files[fd]->keySup);
   }

#ifdef AUDIT_TRAIL
   if (Files[fd]->auditName)
      free (Files[fd]->auditName);
#endif

   free (Files[fd]);
   Files[fd] = 0;
}
static void
_pI__headerLock (FILEDESC isfd, ISBOOL wlck)
{
   if (Files[isfd]->headerLock == ISNOLCK || 
         (Files[isfd]->headerLock == ISRDLCK && wlck)) {
      struct flock lck;
      lck.l_whence = 0;
      lck.l_start = 0;
      lck.l_len = 1;
      lck.l_type = wlck ? F_WRLCK : F_RDLCK;
      if (fcntl(Files[isfd]->fdIndex, F_SETLKW, &lck) == -1) {
         pIserrno = errno;
      } else if (wlck) {
         origSigInt = signal (SIGINT, SIG_IGN);
# ifndef WIN32
         origSigQuit = signal (SIGQUIT, SIG_IGN);
# endif
         origSigTerm = signal (SIGTERM, SIG_IGN);
         Files[isfd]->headerLock =  ISWRLCK;
      } else {
         Files[isfd]->headerLock =  ISRDLCK;
      }
   }
}

static void
_pI__headerUnlock (FILEDESC isfd)
{
   if (Files[isfd]->headerLock != ISNOLCK) {
      struct flock lck;
      lck.l_whence = 0;
      lck.l_start = 0;
      lck.l_len = 1;
      lck.l_type = F_UNLCK;
      if (Files[isfd]->headerLock == ISWRLCK) {
         signal (SIGINT, origSigInt);
# ifndef WIN32
         signal (SIGQUIT, origSigQuit);
# endif
         signal (SIGTERM, origSigTerm);
      }
      if (fcntl(Files[isfd]->fdIndex, F_SETLK, &lck) == -1) {
         pIserrno = errno;
      }
      Files[isfd]->headerLock = ISNOLCK;
   }
}

static void
_pI__testFileLock (FILEDESC isfd)
{
# ifndef WIN32
   struct flock lck;
   lck.l_whence = 0;
   lck.l_start = 1;
   lck.l_len = 0;
   lck.l_type = F_RDLCK;
   if (fcntl(Files[isfd]->fdIndex, F_SETLK, &lck) == -1) {
      pIserrio = errno;
      pIserrno = EFLOCKED;
   }
# endif
}

static void
_pI__fileExLock (FILEDESC isfd)
{
   if (Files[isfd]->fileLock == 0) {
      struct flock lck;
      lck.l_whence = 0;
      lck.l_start = 1;
      lck.l_len = 0;
      lck.l_type = F_WRLCK;
      if (fcntl(Files[isfd]->fdIndex, F_SETLK, &lck) == -1) {
         pIserrio = errno;
         pIserrno = EFLOCKED;
      } else
         Files[isfd]->fileLock = 1;
   }
}

static void
_pI__fileLock (FILEDESC isfd)
{
   if (Files[isfd]->fileLock == 0) {
      struct flock lck;
      lck.l_whence = 0;
      lck.l_start = 0;
      lck.l_len = 0;
      lck.l_type = F_WRLCK;
      if (fcntl(Files[isfd]->fdData, F_SETLK, &lck) == -1) {
         pIserrio = errno;
         pIserrno = EFLOCKED;
      } else
         Files[isfd]->fileLock = 1;
   }
}

static void
_pI__fileUnlock (FILEDESC isfd)
{
   if (Files[isfd]->fileLock == 1) {
      struct flock lck;
      lck.l_whence = 0;
      lck.l_start = 0;
      lck.l_len = 0;
      lck.l_type = F_UNLCK;
      if (fcntl(Files[isfd]->fdData, F_SETLK, &lck) == -1) {
         pIserrio = errno;
      }
      Files[isfd]->fileLock = 0;
   }
}
static Void
_pI__recordLock (FILEDESC isfd, RECNUM recnum, ISBOOL wait)
{
   Void Return = 0;
   if (Files[isfd]->fileLock == 0) {
      SharedFile *shFile = Files[isfd]->dataShFile;
      ISBOOL locked = ISFALSE;
      RecordLock *rl = shFile->lckChain;
      for ( ; rl; rl = rl->next) {
         if (rl->numRec == recnum) {
            locked = ISTRUE;
            if (rl->isfd == isfd)
               break;
         }
      } 
      if (!locked) {
         struct flock lck;
         lck.l_whence = 0;
         lck.l_start = recnum * (Files[isfd]->dictInfo.di_recsize + 1) - 1;
         lck.l_len = 1;
         lck.l_type = F_WRLCK;
         if (fcntl(Files[isfd]->fdData,wait?F_SETLKW:F_SETLK,&lck) == -1) {
            pIserrio = errno;
            pIserrno = ELOCKED;
         } else {
            Files[isfd]->lastRecordLock = recnum;
         }
      }
      if (pIserrno == 0 && rl == 0) {
         rl = (RecordLock *) malloc (sizeof(RecordLock));
         rl->isfd = isfd;
         rl->numRec = recnum;
         rl->next = shFile->lckChain;
         shFile->lckChain = rl;
      }
   }
   return Return;
}

static Void
_pI__recordUnlock (FILEDESC isfd, RECNUM recnum)
{
   Void Return = 0;
   if (Files[isfd]->fileLock == 0) {
      SharedFile *shFile = Files[isfd]->dataShFile;
      ISBOOL locked = ISFALSE;
      RecordLock *rl = shFile->lckChain;
      RecordLock *prl = 0, *nrl;
      while (rl) {
         if (rl->numRec == recnum) {
            locked = ISTRUE;
            nrl = rl->next;
            if (prl == 0)
               shFile->lckChain = rl->next;
            else
               prl->next = rl->next;
            free (rl);
            rl = nrl;
         } else {
            prl = rl;
            rl = rl->next;
         }
      }
      if (locked) {
         struct flock lck;
         lck.l_whence = 0;
         lck.l_start = recnum * (Files[isfd]->dictInfo.di_recsize + 1) - 1;
         lck.l_len = 1;
         lck.l_type = F_UNLCK;
         if (fcntl(Files[isfd]->fdData, F_SETLK, &lck) == -1) {
            pIserrio = errno;
         }
      }
   }
   return Return;
}

static void
_pI__allRecordUnlock (FILEDESC isfd)
{
   if (Files[isfd]->lastRecordLock != 0) {
      SharedFile *shFile = Files[isfd]->dataShFile;
      RecordLock *rl = shFile->lckChain;
      while (rl && rl->isfd == isfd && pIserrno == 0) {
         _pI__recordUnlock (isfd, rl->numRec);
         rl = shFile->lckChain;
      }
      Files[isfd]->lastRecordLock = 0L;
   }
}

static ADDR
_pI__getFreeNode (FILEDESC isfd)
{ 
   ADDR Return;
   static unsigned char buffer[sizeof(short)*2 + sizeof(ADDR)*3 + 2];
   unsigned char *pnt = buffer;
 
   if (Files[isfd]->firstDeletedNode == 0) {
      Return = Files[isfd]->firstFreeNode;
      Files[isfd]->firstFreeNode += Files[isfd]->dictInfo.di_idxsize;
   } else {
      Return = Files[isfd]->firstDeletedNode;
      indexLseek (isfd, Return);
      read(Files[isfd]->fdIndex, pnt, sizeof(buffer));
      pnt++;
      getLongFromBuffer(Files[isfd]->firstDeletedNode, pnt);
   }

   return Return;
}

static ADDR
_pI__allocRecDel (FILEDESC isfd)
{
   ADDR Return = _pI__getFreeNode(isfd);
   unsigned char *pnt;

   memset(Files[isfd]->delrecnode, 0, Files[isfd]->dictInfo.di_idxsize);
   pnt = Files[isfd]->delrecnode;
   *pnt++ = RECDEL_NODE;
   putShortInBuffer(pnt, 0);
   putLongInBuffer(pnt, Files[isfd]->firstDelRecNode);
   Files[isfd]->firstDelRecNode = Return;
   return Return;
}

static Void
_pI__storeRecDel (FILEDESC isfd, RECNUM recnum)
{
   Void Return = 0;
   unsigned char *pnt;
   ADDR addr;
   short numelem = 0;
   short startele = sizeof(short) + sizeof(ADDR) + 1;
   int maxelem = (Files[isfd]->dictInfo.di_idxsize - startele) / sizeof(RECNUM);

   if (Files[isfd]->firstDelRecNode == 0) {
      addr = _pI__allocRecDel (isfd);
      numelem = 0;
   }
   else {
      indexLseek(isfd, Files[isfd]->firstDelRecNode);
      readIndex(isfd, Files[isfd]->delrecnode);
      addr = Files[isfd]->firstDelRecNode;
      pnt = Files[isfd]->delrecnode;
      if (*pnt++ != RECDEL_NODE) {
         pIserrno = EBADFILE;
         return Return;
      }
      getShortFromBuffer(numelem, pnt);
      if (numelem == maxelem) {
         addr = _pI__allocRecDel (isfd);
         numelem = 0;
      }
   }
 
   pnt = Files[isfd]->delrecnode + startele + numelem * sizeof(RECNUM);
   putLongInBuffer(pnt, recnum);
   numelem++;
   pnt = Files[isfd]->delrecnode + 1;
   putShortInBuffer (pnt, numelem);
   indexLseek(isfd, addr);
   writeIndex(isfd, Files[isfd]->delrecnode);
   return Return;
}

static RECNUM
_pI__getRecNum (FILEDESC isfd)
{ 
   RECNUM Return = 0;
   unsigned char *pnt;
   short numelem;
   short startele = sizeof(short) + sizeof(ADDR) + 1;
   ADDR addr = Files[isfd]->firstDelRecNode;
 
   if (Files[isfd]->firstDelRecNode == 0) {
      Return = ++Files[isfd]->dictInfo.di_nrecords;
   } else {
      indexLseek(isfd, Files[isfd]->firstDelRecNode);
      readIndex(isfd, Files[isfd]->delrecnode);
      pnt = Files[isfd]->delrecnode;
      if (*pnt++ != RECDEL_NODE) {
         pIserrno = EBADFILE;
         return Return;
      }
      getShortFromBuffer(numelem, pnt);
      numelem--;
      pnt = Files[isfd]->delrecnode + startele + numelem * sizeof(RECNUM);
      getLongFromBuffer(Return, pnt);
      pnt = Files[isfd]->delrecnode + startele + numelem * sizeof(RECNUM);
      putLongInBuffer(pnt, 0L);
      if (numelem == 0) {
         pnt = Files[isfd]->delrecnode + 1 + sizeof(short);
         getLongFromBuffer(Files[isfd]->firstDelRecNode, pnt);
         pnt = Files[isfd]->delrecnode;
         *pnt++ = DELETED_NODE;
         putLongInBuffer(pnt, Files[isfd]->firstDeletedNode);
         putShortInBuffer(pnt, 0L);
         Files[isfd]->firstDeletedNode = addr;
      } else {
         pnt = Files[isfd]->delrecnode + 1;
         putShortInBuffer(pnt, numelem);
      }
      indexLseek(isfd, addr);
      writeIndex(isfd, Files[isfd]->delrecnode);
   }
   return Return;
}

static void
_pI__resetGetRecNum (FILEDESC isfd, RECNUM recnum)
{ 
   if (recnum == Files[isfd]->dictInfo.di_nrecords - 1)
      --Files[isfd]->dictInfo.di_nrecords;
   else
      _pI__storeRecDel (isfd, recnum);
}

static FILEDESC
_pI__open (char *filename, int openmode)
{
   register int i;
   int len;
   FILEDESC Return = FILEDESC_ERROR;
            pIserrno = ETOOMANY;
 
   for (i = 0; i < MAXOPENFILE; i++)
      if (Files[i] == 0) {
         Files[i] = (FileDesc *) malloc (sizeof(FileDesc));
         memset ((char *) Files[i], 0, sizeof(FileDesc));
         Files[i]->node = 0;
         Files[i]->headerLock = ISNOLCK;
         Files[i]->fileLock = 0;
         Files[i]->lastRecordLock = 0L;
         Files[i]->currIndex = 0;

         setNodeItemDesc(Files[i]->curr,0,0,0,0,0,0);
         setNodeItemDesc(Files[i]->next,0,0,0,0,0,0);

         Files[i]->fdIndex = -1;
         Files[i]->fdData = -1;

         len = strlen (filename);
         Files[i]->indexName = malloc (len + sizeof(INDEX_EXT));
         Files[i]->dataName = malloc (len + sizeof(DATA_EXT));
         sprintf (Files[i]->indexName, "%s%s", filename, INDEX_EXT);
         sprintf (Files[i]->dataName, "%s%s", filename, DATA_EXT);
         Files[i]->node = 0;
# if defined(MSDOS) && !defined(WIN32)
         if (openmode & O_CREAT) {
            if (access (Files[i]->indexName, 0) != 0) {
               if ((Files[i]->fdIndex=_lcreat(Files[i]->indexName, 0))<0 ||
                   (Files[i]->fdData =_lcreat(Files[i]->dataName, 0))<0) {
                  _pI__freeFile (i);
                  pIserrno = errno;
                  pIserrio = errno;
                  Return = FILEDESC_ERROR;
               
               } else {
                  pIserrno = 0;
                  pIserrio = 0;
                  Return = i;
               }    
            } else { 
               _pI__freeFile (i);
               pIserrno = EEXIST;
               pIserrio = EEXIST;
               Return = FILEDESC_ERROR;
            }
         } else
#endif
         if ((Files[i]->fdIndex = 
                     _pI__sharedOpen(Files[i]->indexName,openmode,0666,
                                     &Files[i]->indxShFile))<0 ||
             (Files[i]->fdData =
                     _pI__sharedOpen(Files[i]->dataName, openmode,0666,
                                     &Files[i]->dataShFile))<0) {
            _pI__freeFile (i);
            if (errno == 0)
               pIserrno = EMISSINGFILE;
            else
               pIserrno = errno;
            pIserrio = errno;
            Return = FILEDESC_ERROR;
         } else {
            pIserrno = 0;
            pIserrio = 0;
            Return = i;
         }
         break;
      }
   return Return;
}

static Void
_pI__writeHeader (FILEDESC isfd)
{
   Void Return = 0;
   register short i, j;
   unsigned char * pnt = headerArea;
   short firstNodeNKeys = Files[isfd]->dictInfo.di_nkeys;

   memset(headerArea, 0, Files[isfd]->headerSize);

   if (Files[isfd]->dictInfo.di_nkeys * HEADERKEYSIZE >
       Files[isfd]->headerSize - FIRSTKEYDISP - sizeof(ADDR)) {
      ADDR newNode, nextNode;
      unsigned short offs;
      unsigned short endNode = Files[isfd]->dictInfo.di_idxsize - sizeof(ADDR);
      j = (Files[isfd]->headerSize - FIRSTKEYDISP - sizeof(ADDR))/HEADERKEYSIZE;
      firstNodeNKeys = j;
      if (Files[isfd]->firstAddKeyNode == 0) {
         Files[isfd]->firstAddKeyNode = Files[isfd]->firstFreeNode;
         Files[isfd]->firstFreeNode += Files[isfd]->dictInfo.di_idxsize;
         nextNode = 0L;
         memset(Files[isfd]->node, 0,
                Files[isfd]->dictInfo.di_idxsize);
      } else {
         indexLseek (isfd, Files[isfd]->firstAddKeyNode);
         readIndex (isfd, Files[isfd]->node);
         pnt = &Files[isfd]->node[endNode];
         getLongFromBuffer (nextNode, pnt);
         memset(Files[isfd]->node, 0,
                Files[isfd]->dictInfo.di_idxsize - sizeof(ADDR));
      }
      pnt = Files[isfd]->node;
      *pnt++ = KEY_NODE;
      offs = 1;
      indexLseek (isfd, Files[isfd]->firstAddKeyNode);
      for ( ; j < Files[isfd]->dictInfo.di_nkeys; j++) {
         if ((offs += HEADERKEYSIZE) > endNode) {
            if (nextNode == 0) {
               newNode = Files[isfd]->firstFreeNode;
               Files[isfd]->firstFreeNode += Files[isfd]->dictInfo.di_idxsize;
            } else {
               newNode = nextNode;
            }
            pnt = &Files[isfd]->node[endNode];
            putLongInBuffer(pnt, newNode);
            if (write (Files[isfd]->fdIndex,
                       Files[isfd]->node,
                       Files[isfd]->dictInfo.di_idxsize) !=
                Files[isfd]->dictInfo.di_idxsize) {
               pIserrno = pIserrio = errno;
               _pI__freeFile (isfd);
               return Return;
            }
            if (nextNode == 0) {
               memset(Files[isfd]->node, 0,
                      Files[isfd]->dictInfo.di_idxsize);
            } else {
               indexLseek (isfd, newNode);
               readIndex (isfd, Files[isfd]->node);
               pnt = &Files[isfd]->node[endNode];
               getLongFromBuffer (nextNode, pnt);
               memset(Files[isfd]->node, 0,
                      Files[isfd]->dictInfo.di_idxsize - sizeof(ADDR));
            }
            pnt = Files[isfd]->node;
            *pnt++ = KEY_NODE;
            offs = HEADERKEYSIZE + 1;
            indexLseek (isfd, newNode);
         }
         putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_flags);
         putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_nparts);
         for (i = 0; i < Files[isfd]->keyDesc[j]->k_nparts; i++) {
            putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_part[i].kp_start);
            putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_part[i].kp_leng);
            putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_part[i].kp_type);
         }
         pnt += sizeof(short) * 3 * (NPARTS - i);
         putShortInBuffer(pnt,Files[isfd]->keyDesc[j]->k_len);
         putLongInBuffer(pnt,Files[isfd]->keyDesc[j]->k_rootnode);
      }
      if (write (Files[isfd]->fdIndex,
                 Files[isfd]->node,
                 Files[isfd]->dictInfo.di_idxsize) !=
          Files[isfd]->dictInfo.di_idxsize) {
         pIserrno = pIserrio = errno;
         _pI__freeFile (isfd);
         return Return;
      }
   }
   pnt = headerArea;
   indexLseek (isfd, 0L);
/* 0-5 Signature */
   memcpy (pnt, SIGN, 6);
   pnt+=6;
/* 6-7 Release */
   putShortInBuffer(pnt,Files[isfd]->releaseLevel);

/* 8-11 first free node */
   putLongInBuffer(pnt, Files[isfd]->firstFreeNode);

/* 12-13 number of keys */
   putShortInBuffer(pnt,Files[isfd]->dictInfo.di_nkeys);
/* 14-15 recsize  */
   putShortInBuffer(pnt,Files[isfd]->dictInfo.di_recsize);
/* 16-17 index record size  */
   putShortInBuffer(pnt,Files[isfd]->dictInfo.di_idxsize);
/* 18-21 number of record */
   putLongInBuffer(pnt,Files[isfd]->dictInfo.di_nrecords);
/* 22-23 header dimension */
   putShortInBuffer(pnt, Files[isfd]->headerSize);
/* 24-27 first deleted node */
   putLongInBuffer(pnt, Files[isfd]->firstDeletedNode);
/* 28-31 first deleted record node */
   putLongInBuffer(pnt, Files[isfd]->firstDelRecNode);
/* <last four bytes> first additional key node */
   pnt = headerArea + Files[isfd]->headerSize - sizeof(ADDR);
   putLongInBuffer(pnt, Files[isfd]->firstAddKeyNode);
  
   pnt = headerArea + FIRSTKEYDISP;

   for (j = 0; j < firstNodeNKeys; j++) {
      putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_flags);
      putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_nparts);
      for (i = 0; i < Files[isfd]->keyDesc[j]->k_nparts; i++) {
         putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_part[i].kp_start);
         putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_part[i].kp_leng);
         putShortInBuffer(pnt, Files[isfd]->keyDesc[j]->k_part[i].kp_type);
      }
      pnt += sizeof(short) * 3 * (NPARTS - i);
      putShortInBuffer(pnt,Files[isfd]->keyDesc[j]->k_len);
      putLongInBuffer(pnt,Files[isfd]->keyDesc[j]->k_rootnode);
   }
   if (write (Files[isfd]->fdIndex, headerArea, Files[isfd]->headerSize) !=
                                                Files[isfd]->headerSize) {
      pIserrno = pIserrio = errno;
      _pI__freeFile (isfd);
   }
   return Return;
}

static Void
_pI__readHeader (FILEDESC isfd, ISBOOL wlck)
{
   Void Return = 0;
   unsigned char *pnt;
   static unsigned char header[FIRSTKEYDISP];
   register short i, j;
   short reminder;
   short nkeys; 
   short firstNodeNKeys;

   indexLseek (isfd, 0L);
   _pI__headerLock (isfd, wlck);
   if (read (Files[isfd]->fdIndex, header, FIRSTKEYDISP) < FIRSTKEYDISP) {
      pIserrio = errno;
      pIserrno = EBADFILE;
      _pI__freeFile (isfd);
      return Return;
   }
      
   pnt = header;

/* 0-5 Signature */
   
   if (memcmp(pnt, SIGN, 6) != 0) {
      pIserrno = EBADFILE;
      _pI__freeFile (isfd);
      RETURN
   }
   pnt += 6;
/* 6-7 Release */
   getShortFromBuffer(Files[isfd]->releaseLevel, pnt);
   if (Files[isfd]->releaseLevel < 0 ||
       Files[isfd]->releaseLevel > 1)  {
      pIserrno = EBADFILE;
      _pI__freeFile (isfd);
      RETURN
   }


/* 8-11 first free node */
   getLongFromBuffer(Files[isfd]->firstFreeNode, pnt);

/* 12-13 number of keys */
   getShortFromBuffer(nkeys, pnt);
/* 14-15 recsize  */
   getShortFromBuffer(Files[isfd]->dictInfo.di_recsize,pnt);
/* 16-17 index record size  */
   getShortFromBuffer(Files[isfd]->dictInfo.di_idxsize,pnt);
/* 18-21 number of record */
   getLongFromBuffer(Files[isfd]->dictInfo.di_nrecords,pnt);
/* 22-23 header dimension */
   getShortFromBuffer(Files[isfd]->headerSize, pnt);
/* 24-27 first deleted node */
   getLongFromBuffer(Files[isfd]->firstDeletedNode, pnt);
/* 28-31 first deleted record node */
   getLongFromBuffer(Files[isfd]->firstDelRecNode, pnt);

   if (Files[isfd]->dictInfo.di_nkeys < nkeys)
      _pI__allocKey (isfd,
                     Files[isfd]->dictInfo.di_nkeys, nkeys);
   Files[isfd]->dictInfo.di_nkeys = nkeys;

   reminder = Files[isfd]->headerSize - FIRSTKEYDISP;

   if (read (Files[isfd]->fdIndex, headerArea, reminder) < reminder) {
      pIserrio = errno;
      pIserrno = EBADFILE;
      _pI__freeFile (isfd);
      return Return;
   }
/* <last four bytes> first additional key node */
   firstNodeNKeys = Files[isfd]->dictInfo.di_nkeys;
   pnt = headerArea + reminder - sizeof(ADDR);
   getLongFromBuffer(Files[isfd]->firstAddKeyNode, pnt);
   if (Files[isfd]->dictInfo.di_nkeys * HEADERKEYSIZE >
       Files[isfd]->headerSize - FIRSTKEYDISP - sizeof(ADDR)) {
      ADDR newNode = Files[isfd]->firstAddKeyNode;
      unsigned short endNode = Files[isfd]->dictInfo.di_idxsize - sizeof(ADDR);
      unsigned short offs = endNode;
      i = (Files[isfd]->headerSize - FIRSTKEYDISP - sizeof(ADDR))/HEADERKEYSIZE;
      firstNodeNKeys = i;
      for ( ; i < Files[isfd]->dictInfo.di_nkeys; i++){
         if ((offs += HEADERKEYSIZE) > endNode) {
            if (newNode == 0) {
               pIserrno = EBADFILE;
               _pI__freeFile (isfd);
               return Return;
            }
            indexLseek (isfd, newNode);
            readIndex (isfd, Files[isfd]->node);
            pnt = &Files[isfd]->node[endNode];
            getLongFromBuffer (newNode, pnt);
            pnt = Files[isfd]->node;
            if (*pnt++ != KEY_NODE) {
               pIserrno = EBADFILE;
               _pI__freeFile (isfd);
               return Return;
            } 
            offs =  HEADERKEYSIZE + 1;
         }
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_flags, pnt);
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_nparts, pnt);
         for (j = 0; j < Files[isfd]->keyDesc[i]->k_nparts; j++) {
            getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_start, pnt);
            getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_leng, pnt);
            getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_type, pnt);
         }
         pnt += sizeof(short) * 3 * (NPARTS - j);
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_len,pnt);
         getLongFromBuffer(Files[isfd]->keyDesc[i]->k_rootnode,pnt);
      }
   }
  
   pnt = headerArea;
   for (i = 0; i < firstNodeNKeys; i++){
      getShortFromBuffer(Files[isfd]->keyDesc[i]->k_flags, pnt);
      getShortFromBuffer(Files[isfd]->keyDesc[i]->k_nparts, pnt);
      for (j = 0; j < Files[isfd]->keyDesc[i]->k_nparts; j++) {
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_start, pnt);
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_leng, pnt);
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_type, pnt);
      }
      pnt += sizeof(short) * 3 * (NPARTS - j);
      getShortFromBuffer(Files[isfd]->keyDesc[i]->k_len,pnt);
      getLongFromBuffer(Files[isfd]->keyDesc[i]->k_rootnode,pnt);
   }
   return Return;
}

static void
_pI__buildKey (FILEDESC isfd, short keynum, unsigned char *record,
               unsigned char *pnt)
{
   register short i;

   for (i = 0; i < Files[isfd]->keyDesc[keynum]->k_nparts; i++) {
      memcpy (pnt, &record[Files[isfd]->keyDesc[keynum]->k_part[i].kp_start],
                           Files[isfd]->keyDesc[keynum]->k_part[i].kp_leng);
      pnt += Files[isfd]->keyDesc[keynum]->k_part[i].kp_leng;
   }
   *pnt = 0;
}

static double doubleRet;
static float floatRet;
static long longRet;
static short
_pI__keyCmp (unsigned char * k1, unsigned char *k2, struct keydesc *kdesc)
{
   register int i;
   short Return = 0;

   if (kdesc->k_nparts > 0)
      for (i = 0; i < kdesc->k_nparts && Return == 0; i++)
         switch (kdesc->k_part[i].kp_type & 0x0F) {
         case CHARTYPE:
            Return = memcmp (k1, k2, kdesc->k_part[i].kp_leng);
            if (kdesc->k_part[i].kp_type & ISDESC)
               Return *= -1;
            k1 += kdesc->k_part[i].kp_leng;
            k2 += kdesc->k_part[i].kp_leng;
            break;
         case INTTYPE:
            if (*((INT2 *) k1) == NULLSHORT)
               if (*((INT2 *) k2) == NULLSHORT)
                  Return = 0;
               else
                  Return = -1;
            else
               if (*((INT2 *) k2) == NULLSHORT)
                  Return = 1;
               else
                  Return = *((INT2 *) k1) - *((INT2 *) k2);
            if (kdesc->k_part[i].kp_type & ISDESC)
               Return = -Return;
            k1 += sizeof (INT2);
            k2 += sizeof (INT2);
            break;
         case LONGTYPE:
            if (*((INT4 *) k1) == NULLLONG)
               if (*((INT4 *) k2) == NULLLONG)
                  Return = 0;
               else
                  Return = -1;
            else
               if (*((INT4 *) k2) == NULLLONG)
                  Return = 1;
               else {
                  longRet = *((INT4 *) k1) - *((INT4 *) k2);
                  Return = longRet > 0 ? 1 : (longRet < 0 ? -1 : 0);
               }
            if (kdesc->k_part[i].kp_type & ISDESC)
               Return *= -1;
            k1 += sizeof (INT4);
            k2 += sizeof (INT4);
            break;
         case DOUBLETYPE:
            doubleRet = *((double *) k1) - *((double *) k2);
            Return = doubleRet > 0 ? 1 : (doubleRet < 0 ? -1 : 0);
            if (kdesc->k_part[i].kp_type & ISDESC)
               Return *= -1;
            k1 += sizeof (double);
            k2 += sizeof (double);
            break;
         case FLOATTYPE:
            floatRet = *((float *) k1) - *((float *) k2);
            Return = floatRet > 0 ? 1 : (floatRet < 0 ? -1 : 0);
            if (kdesc->k_part[i].kp_type & ISDESC)
               Return *= -1;
            k1 += sizeof (float);
            k2 += sizeof (float);
            break;
     }
   else
      Return = -1;
   return Return;
}

static short
_pI__searchGtLeaf (NodeDesc *node, unsigned char *keyArea,
                   struct keydesc *kdesc, int dup)
{
   register int i;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;

   for (i = 0; i < node->numElem; i++)
      if (_pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc) > 0)
         break;

   return i;
}

static short
_pI__searchGeLeaf (NodeDesc *node, unsigned char *keyArea,
                   struct keydesc *kdesc, int dup)
{
   register int i;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;

   for (i = 0; i < node->numElem; i++)
      if (_pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc) >= 0)
         break;

   return i;
}

static short
_pI__searchGeBranch (NodeDesc *node, unsigned char *keyArea,
                     struct keydesc *kdesc)
{
   register int i;
   int tksz = node->kdesc->k_len+sizeof(RECNUM);

   for (i = 0; i < node->numElem - 1; i++)
      if (_pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc) >= 0)
         break;

   return i;
}

static short
_pI__searchGtBranch (NodeDesc *node, unsigned char *keyArea,
                   struct keydesc *kdesc)
{
   register int i;
   int tksz = node->kdesc->k_len+sizeof(RECNUM);

   for (i = 0; i < node->numElem - 1; i++)
      if (_pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc) > 0)
         break;

   return i;
}

static NodeItemDesc *
_pI__searchEqInNode (NodeDesc *node, unsigned char *keyArea,
                     struct keydesc *kdesc, int dup, int *rc)
{
   register int i;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;
   *rc = -1;

   for (i = 0; i < node->numElem && *rc < 0; i++)
      if ((*rc = _pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc)) == 0) {
         getKeyDesc(found,i,node);
         break;
      }
   return Return;
}

static NodeItemDesc *
_pI__searchRevEqInNode (NodeDesc *node, unsigned char *keyArea,
                        struct keydesc *kdesc, int dup, int *cfrt)
{
   register int i;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;

   for (i = node->numElem - 1; i >= 0; i--)
      if ((*cfrt = _pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc))<=0) {
         if (*cfrt == 0) {
            getKeyDesc(found,i,node);
         }
         break;
      }
   return Return;
}

static NodeItemDesc *
_pI__searchGtInNode (NodeDesc *node, unsigned char *keyArea,
                   struct keydesc *kdesc, int dup)
{
   register int i;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;

   for (i = 0; i < node->numElem; i++)
      if (_pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc) > 0) {
         getKeyDesc(found,i,node);
         break;
      }
   return Return;
}

static NodeItemDesc *
_pI__searchGeInNode (NodeDesc *node, unsigned char *keyArea,
                   struct keydesc *kdesc, int dup, int *rc)
{
   register int i;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;
   *rc = -1;

   for (i = 0; i < node->numElem && *rc < 0; i++)
      if ((*rc = _pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc)) >= 0) {
         getKeyDesc(found,i,node);
         break;
      }
   return Return;
}

static NodeItemDesc *
_pI__searchLtInNode (NodeDesc *node, unsigned char *keyArea,
                     struct keydesc *kdesc, int dup)
{
   register int i;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;

   for (i = node->numElem - 1; i >= 0; i--)
      if (_pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc) < 0) {
         getKeyDesc(found,i,node);
         break;
      }
   return Return;
}

static NodeItemDesc *
_pI__searchLeInNode (NodeDesc *node, unsigned char *keyArea,
                   struct keydesc *kdesc, int dup)
{
   register int i;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;

   for (i = node->numElem - 1; i >= 0; i--)
      if (_pI__keyCmp(&node->nodeArea[i * tksz], keyArea, kdesc) <= 0) {
         getKeyDesc(found,i,node);
         break;
      }
   return Return;
}

static NodeItemDesc *
_pI__searchFirstInNode (NodeDesc *node, int dup)
{
   register int i = 0;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;

   if (node->numElem  > 0) {
      getKeyDesc(found,i,node);
   }
   return Return;
}

static NodeItemDesc *
_pI__searchLastInNode (NodeDesc *node, int dup)
{
   register int i = node->numElem - 1;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;

   if (node->numElem  > 0) {
      getKeyDesc(found,i,node);
   }
   return Return;
}

static void
_pI__branchInsert (NodeDesc *node, short pos, unsigned char *key,
                   RECNUM numrec, int dup, PROG keyProg)
{
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   unsigned char *pnt = &node->nodeArea[pos * tksz];
   register unsigned char *ipnt;

   for (ipnt = &node->nodeArea[node->numElem * tksz]; ipnt > pnt; ipnt -= tksz)
      memcpy (ipnt, ipnt - tksz, tksz);
   memcpy (pnt, key, node->kdesc->k_len);
   pnt += node->kdesc->k_len;
   if (dup)
      putLongInBuffer(pnt,keyProg);
   putLongInBuffer(pnt,numrec);

   node->numElem++;
}

static RECNUM
_pI__leafInsert (FILEDESC isfd, NodeDesc *node, unsigned char *key,
                 RECNUM numrec, int dup, PROG keyProg)
{
   RECNUM Return = numrec;
   unsigned char *pnt;
   short pos;

   if (node->numElem == 0) {
      pnt = node->nodeArea;
      memcpy(pnt, key, node->kdesc->k_len);
      pnt += node->kdesc->k_len;
      if (dup)
         putLongInBuffer(pnt,keyProg);
      putLongInBuffer(pnt,Return);
      node->numElem++;
   } else {
      if (Files[isfd]->releaseLevel == 1)
         pos = _pI__searchGtLeaf (node, key, node->kdesc, dup);
      else
         pos = _pI__searchGeLeaf (node, key, node->kdesc, dup);
      _pI__branchInsert (node, pos, key, Return, dup, keyProg);
   }

   return Return;
}

static Void
_pI__readNode (FILEDESC isfd, short keynum, ADDR addr,
                unsigned char *buffer, NodeDesc *thisNode)
{
   int psz = (isKeyDup(isfd,keynum) ? sizeof(PROG) : 0);
   int tksz = Files[isfd]->keyDesc[keynum]->k_len + sizeof(RECNUM) + psz;
   unsigned char *pnt = buffer;
   Void Return = 0;

   indexLseek (isfd, addr);
   readIndex (isfd, pnt);

   thisNode->nodeType = *pnt++;
   getShortFromBuffer (thisNode->numElem, pnt);
   getLongFromBuffer (thisNode->leftBrot, pnt);
   getLongFromBuffer (thisNode->rightBrot, pnt);

   thisNode->nodeAddr   = addr;
   thisNode->usableSize = Files[isfd]->dictInfo.di_idxsize -
                        (long) (pnt - buffer);
   thisNode->kdesc = Files[isfd]->keyDesc[keynum];
   if (thisNode->nodeType == BRANCH_NODE)
      tksz -= psz;
   thisNode->maxElem = thisNode->usableSize/tksz;
   thisNode->nodeArea = pnt;
   return Return;
}

static Void
_pI__writeNode (FILEDESC isfd, unsigned char *buffer, NodeDesc *thisNode)
{
   unsigned char *pnt = buffer;
   Void Return = 0;

   *pnt++ = thisNode->nodeType;
   putShortInBuffer (pnt, thisNode->numElem);
   putLongInBuffer (pnt, thisNode->leftBrot);
   putLongInBuffer (pnt, thisNode->rightBrot);
   if (pnt != thisNode->nodeArea)
      memcpy (pnt, thisNode->nodeArea, thisNode->usableSize);

   indexLseek (isfd, thisNode->nodeAddr);
   writeIndex (isfd, buffer);

   return Return;
}

static ADDR
_pI__newRoot (NewNodes *kaa, FILEDESC isfd, short keynum)
{
   ADDR Return = _pI__getFreeNode (isfd);
   unsigned char * pnt;
   NodeDesc thisNode;

   memset (Files[isfd]->node, 0, Files[isfd]->dictInfo.di_idxsize);
   pnt = Files[isfd]->node;

   thisNode.nodeType = BRANCH_NODE;
   pnt++;
   thisNode.numElem = 2;
   pnt += sizeof(short);
   thisNode.leftBrot = 0L;
   pnt += sizeof(ADDR);
   thisNode.rightBrot = 0L;
   pnt += sizeof(ADDR);

   thisNode.nodeAddr   = Return;
   thisNode.usableSize = Files[isfd]->dictInfo.di_idxsize -
                        (long) (pnt - Files[isfd]->node);
   thisNode.kdesc = Files[isfd]->keyDesc[keynum];
   thisNode.maxElem = thisNode.usableSize/(thisNode.kdesc->k_len+sizeof(ADDR));
   thisNode.nodeArea = pnt;

   memcpy (pnt, kaa->keyValMin, Files[isfd]->keyDesc[keynum]->k_len);
   pnt += Files[isfd]->keyDesc[keynum]->k_len;
   putLongInBuffer (pnt, kaa->nodeAddrKMin);
   memset (pnt, 0xFF, Files[isfd]->keyDesc[keynum]->k_len);
   pnt += Files[isfd]->keyDesc[keynum]->k_len;
   putLongInBuffer (pnt, kaa->nodeAddrKMax);
   _pI__writeNode (isfd, Files[isfd]->node, &thisNode);

   return Return;
}

static Void
_pI__changeLeftBrother (ADDR thisAddr, ADDR rightAddr, FILEDESC isfd, int type)
{
   Void Return = 0;
   unsigned char * pnt = Files[isfd]->node;

   indexLseek (isfd, thisAddr);
   readIndex (isfd, pnt);

   if (*pnt++ != type) {
      pIserrno = EBADFILE;
      return Return;
   }
   pnt += sizeof(short) + sizeof(ADDR);
   putLongInBuffer (pnt, rightAddr);
   indexLseek (isfd, thisAddr);
   writeIndex (isfd, Files[isfd]->node);
   return Return;
}

static Void
_pI__changeRightBrother (ADDR thisAddr, ADDR leftAddr, FILEDESC isfd, int type)
{
   Void Return = 0;
   unsigned char * pnt = Files[isfd]->node;

   indexLseek (isfd, thisAddr);
   readIndex (isfd, pnt);

   if (*pnt++ != type) {
      pIserrno = EBADFILE;
      return Return;
   }
   pnt += sizeof(short);
   putLongInBuffer (pnt, leftAddr);
   indexLseek (isfd, thisAddr);
   writeIndex (isfd, Files[isfd]->node);
   return Return;
}

static NewNodes *
_pI__breakNode (NodeDesc *node, short keynum, short pos, unsigned char *key,
                RECNUM numrec, FILEDESC isfd, int type, int dup, PROG keyProg)
{
   short numElemNew = (node->numElem + 1) / 2;
   short numElemOld = node->numElem - numElemNew + 1;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + psz;
   NodeDesc newNode;
   static NewNodes kaa;
   NewNodes * Return = 0;
   unsigned char *nodeBuf = malloc (Files[isfd]->dictInfo.di_idxsize + tksz);
   unsigned char * pntSx = nodeBuf;
   unsigned char * pntRx = Files[isfd]->node;
   unsigned char * pntWork;
   register int i;

   kaa.nodeAddrKMin = _pI__getFreeNode(isfd);
   kaa.nodeAddrKMax = node->nodeAddr;

   memset (nodeBuf, 0, Files[isfd]->dictInfo.di_idxsize + tksz);
   pntWork = nodeBuf;
   *pntWork++ = type;
   putShortInBuffer (pntWork, node->numElem);
   putLongInBuffer (pntWork, node->leftBrot);
   putLongInBuffer (pntWork, node->rightBrot);

   memcpy (pntWork, node->nodeArea, node->numElem * tksz);
   memcpy ((unsigned char *) &newNode, node, sizeof(NodeDesc));
   newNode.nodeArea = pntWork;
   if (type == LEAF_NODE)
      _pI__leafInsert (isfd, &newNode, key, numrec, dup, keyProg);
   else
      _pI__branchInsert (&newNode, pos, key, numrec, dup, keyProg);

   memset (pntRx, 0, Files[isfd]->dictInfo.di_idxsize);
   for (i = numElemNew - 1; numElemNew < node->maxElem; i++)
      if (_pI__keyCmp(&newNode.nodeArea[i * tksz], 
                      &newNode.nodeArea[(i + 1) * tksz], node->kdesc) == 0)
         numElemNew++;
      else
         break;
   numElemOld = node->numElem - numElemNew + 1;

   memcpy (kaa.keyValMin, &newNode.nodeArea[(numElemNew - 1) * tksz],
           node->kdesc->k_len);
   memcpy (kaa.keyValMax, &newNode.nodeArea[node->numElem * tksz],
           node->kdesc->k_len);

/* nodo vecchio con chiave massima */
   *pntRx++ = type;
   putShortInBuffer (pntRx, numElemOld);
   putLongInBuffer (pntRx, kaa.nodeAddrKMin);
   putLongInBuffer (pntRx, node->rightBrot);
   memcpy (pntRx, &newNode.nodeArea[numElemNew * tksz], numElemOld * tksz);
   indexLseek (isfd, kaa.nodeAddrKMax);
   writeIndex (isfd, Files[isfd]->node);

/* nodo nuovo con chiave minima */
   *pntSx++ = type;
   putShortInBuffer (pntSx, numElemNew);
   putLongInBuffer (pntSx, node->leftBrot);
   putLongInBuffer (pntSx, kaa.nodeAddrKMax);
   memset (&newNode.nodeArea[numElemNew * tksz], 0, numElemOld * tksz);
   indexLseek (isfd, kaa.nodeAddrKMin);
   writeIndex (isfd, nodeBuf);

   if (node->leftBrot != 0)
     _pI__changeLeftBrother (node->leftBrot, kaa.nodeAddrKMin, isfd, type);
   free (nodeBuf);
   return (Return = &kaa);
}

typedef struct tRecProg {
   RECNUM recNum;
   PROG keyProg;
} RecProg;

static RecProg
_pI__shiftToLastKey (FILEDESC isfd, NodeDesc *node, NodeItemDesc * newn,
                     struct keydesc *kdesc, int keypos, int keynum)
{
   register int i;
   int tksz = node->kdesc->k_len+sizeof(RECNUM) + sizeof(PROG);
   RecProg Return;
   RecProg nextRP;
   NodeDesc newNode;
   char *pnt;
   
   Return.recNum = 0;

   for (i = keypos, pnt = &node->nodeArea[keypos * tksz];
        i < node->numElem;
        i++, pnt += tksz)
      if (_pI__keyCmp(pnt, newn->keyVal, kdesc) != 0)
         break;
      else {
         newn->keyProg = pntohl(pnt +  node->kdesc->k_len) + 1;
         if (Return.recNum == 0) {
            Return.recNum = 
                   pntohl(pnt +  node->kdesc->k_len + sizeof(RECNUM));
            Return.keyProg = pntohl(pnt +  node->kdesc->k_len);
         } else
            memcpy (pnt - tksz, pnt, tksz);
      }
   if (i > 0) {
      pnt -= sizeof(PROG) + sizeof(RECNUM);
      if (i < node->numElem || node->rightBrot == 0) {
         putLongInBuffer(pnt,newn->keyProg);
         putLongInBuffer(pnt,newn->numRec);
      } else {
         char *buf = malloc (Files[isfd]->dictInfo.di_idxsize);
         _pI__readNode (isfd, keynum, node->rightBrot, buf, &newNode);
         nextRP = _pI__shiftToLastKey (isfd, &newNode, newn,
                                       kdesc, 0, keynum); 
         if (nextRP.recNum == 0)  {
            putLongInBuffer(pnt,newn->keyProg);
            putLongInBuffer(pnt,newn->numRec);
         } else { 
             _pI__writeNode (isfd, buf, &newNode);
            putLongInBuffer(pnt,nextRP.keyProg);
            putLongInBuffer(pnt,nextRP.recNum);
         }
         free(buf);                                                                     
      }
   }
   return Return;
}

static NewNodes *
_pI__insertKey (unsigned char * key, ADDR node,
                short keynum, int isfd, RECNUM recNum)
{
   NodeDesc thisNode;
   NewNodes * Return = 0;
   short nextNodePos;
   NodeItemDesc * found;
   PROG keyProg;
   int rc;

   _pI__readNode (isfd, keynum, node, Files[isfd]->node, &thisNode);
   if (pIserrno != 0)
      return Return;

   if (thisNode.nodeType == LEAF_NODE) {
      if (Files[isfd]->releaseLevel == 1) {
         int cfrt = 0;
         found = _pI__searchRevEqInNode (&thisNode, key,
                           thisNode.kdesc, isKeyDup(isfd, keynum), &cfrt);
         if (isKeyDup(isfd, keynum))
            if (found == 0)
               if (cfrt >= 0 && thisNode.leftBrot != 0) {
                  NodeItemDesc *last;
                  NodeDesc newNode;
                  ADDR newAddr = thisNode.leftBrot;
                  char *buf = malloc (Files[isfd]->dictInfo.di_idxsize);
                  do {
                     _pI__readNode (isfd,keynum,newAddr,buf,&newNode);
                     newAddr = newNode.leftBrot;
                  } while (newNode.numElem == 0 && newAddr != 0);
                  last = _pI__searchLastInNode (&newNode, 1);
                  if (last) 
                     keyProg = last->keyProg + 1;
                  else
                     keyProg = 0;
                  free (buf);
               } else
                  keyProg = 0;
            else 
               keyProg = found->keyProg + 1;
         else 
            if (found != 0) {
               pIserrno = EDUPL;
               return Return;
            } else
               keyProg = 0;
      } else {
         found = _pI__searchEqInNode (&thisNode, key,
                             thisNode.kdesc, isKeyDup(isfd, keynum), &rc);
         if (isKeyDup(isfd, keynum))
            if (found == 0)
               keyProg = 0;
            else 
               keyProg = found->keyProg + 1;
         else 
            if (found != 0) {
               pIserrno = EDUPL;
               return Return;
            } else
               keyProg = 0;
      }
      if (thisNode.maxElem > thisNode.numElem) {
         recNum = _pI__leafInsert (isfd, &thisNode, key, recNum,
                                    isKeyDup(isfd, keynum), keyProg);
         _pI__writeNode (isfd, Files[isfd]->node, &thisNode);
         Return = 0;
      } else
         Return = _pI__breakNode(&thisNode,keynum,0,key,recNum,isfd,
                  LEAF_NODE, isKeyDup(isfd, keynum), keyProg);

   } else if (thisNode.nodeType == BRANCH_NODE) {
      if (Files[isfd]->releaseLevel == 1 && isKeyDup(isfd, keynum))
         nextNodePos = _pI__searchGtBranch (&thisNode, key, thisNode.kdesc);
      else
         nextNodePos = _pI__searchGeBranch (&thisNode, key, thisNode.kdesc);
      Return = _pI__insertKey (key, getNumRec(thisNode,nextNodePos),
                               keynum, isfd, recNum);
      if (pIserrno != 0)
         return Return;
      else if (Return != 0 ) {
         _pI__readNode (isfd, keynum, node, Files[isfd]->node, &thisNode);
         if (pIserrno != 0)
            return Return;
         if (thisNode.maxElem > thisNode.numElem) {
            _pI__branchInsert (&thisNode, nextNodePos,
                               Return->keyValMin, Return->nodeAddrKMin, 0,0);
            _pI__writeNode (isfd, Files[isfd]->node, &thisNode);
            Return = 0;
         }  else
            Return = _pI__breakNode(&thisNode,keynum,nextNodePos,
                   Return->keyValMin, Return->nodeAddrKMin, isfd,
                   BRANCH_NODE, 0, 0);
      }
   } else {
      pIserrno = EBADFILE;
   }
   return Return;
}


static NodeItemDesc *
_pI__findKey (unsigned char * key, ADDR addr,
          short keynum, FILEDESC isfd, struct keydesc *kdesc, int mode, int dup)
{
   NodeDesc thisNode;
   NodeItemDesc * Return = 0;
   short nextNodePos;
   int rc;

   if (addr == 0)
      return Return;
   _pI__readNode (isfd, keynum, addr, Files[isfd]->node, &thisNode);
   if (pIserrno != 0)
      return Return;

   if (thisNode.nodeType == LEAF_NODE) {
      if (thisNode.numElem == 0)
         if (mode == ISLAST || mode == ISLTEQ)
            Return = _pI__findKey(key,thisNode.leftBrot,keynum,
                                  isfd,kdesc,mode,dup);
         else
            Return = _pI__findKey(key,thisNode.rightBrot,keynum,
                                  isfd,kdesc,mode,dup);
      else
         switch (mode) {
         case ISLAST:
            Return = _pI__searchLastInNode (&thisNode, dup);
            break;
         case ISFIRST:
            Return = _pI__searchFirstInNode (&thisNode, dup);
            break;
         case ISEQUAL:
            Return = _pI__searchEqInNode (&thisNode, key, kdesc, dup, &rc);
            if (Return == 0 && rc < 0 && thisNode.rightBrot != 0L)
                Return = _pI__findKey (key, thisNode.rightBrot,
                                       keynum, isfd, kdesc, mode, dup);
            break;
         case ISGTEQ:
            Return = _pI__searchGeInNode (&thisNode, key, kdesc, dup, &rc);
            if (Return == 0 && rc < 0 && thisNode.rightBrot != 0L)
                Return = _pI__findKey (key, thisNode.rightBrot,
                                       keynum, isfd, kdesc, mode, dup);
            break;
         case ISGREAT:
            Return = _pI__searchGtInNode (&thisNode, key, kdesc, dup);
            if (Return == 0 && thisNode.rightBrot != 0L)
                Return = _pI__findKey (key, thisNode.rightBrot,
                                       keynum, isfd, kdesc, mode, dup);
            break;
         case ISLTEQ:
            Return = _pI__searchLeInNode (&thisNode, key, kdesc, dup);
            if (Return == 0 && thisNode.leftBrot != 0L)
                Return = _pI__findKey (key, thisNode.leftBrot,
                                       keynum, isfd, kdesc, mode, dup);
            break;
         case ISLESS:
            Return = _pI__searchLtInNode (&thisNode, key, kdesc, dup);
            if (Return == 0 && thisNode.leftBrot != 0L)
                Return = _pI__findKey (key, thisNode.leftBrot,
                                       keynum, isfd, kdesc, mode, dup);
            break;
         default:
            pIserrno = EBADARG;
            return Return;
         }
   } else if (thisNode.nodeType == BRANCH_NODE) {
      switch (mode) {
      case ISLAST:
         nextNodePos = thisNode.numElem - 1;
         Return = _pI__findKey (key, getNumRec(thisNode,nextNodePos),
                                keynum, isfd, kdesc, mode, dup);
         break;
      case ISFIRST:
         nextNodePos = 0;
         Return = _pI__findKey (key, getNumRec(thisNode,nextNodePos),
                                keynum, isfd, kdesc, mode, dup);
         break;
      case ISEQUAL:
      case ISGTEQ:
      case ISLESS:
         nextNodePos =_pI__searchGeBranch (&thisNode, key, kdesc);
         Return = _pI__findKey (key, getNumRec(thisNode,nextNodePos),
                                keynum, isfd, kdesc, mode, dup);
         break;
      case ISGREAT:
      case ISLTEQ: /* nella ISLTEQ bisogna trovare il piu' alto */
         nextNodePos =_pI__searchGtBranch (&thisNode, key, kdesc);
         Return = _pI__findKey (key, getNumRec(thisNode,nextNodePos),
                                keynum, isfd, kdesc, mode, dup);
         break;
      default:
         pIserrno = EBADARG;
         return Return;
      }
   } else {
      pIserrno = EBADFILE;
   }
   return Return;
}

static RECNUM
_pI__verifyCurr(FILEDESC isfd, short keynum, unsigned char *key,
                ADDR addr, PROG kprog, int dup)
{
   RECNUM Return = 0;
   register int i;
   long rc;
   NodeDesc node;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz;

   _pI__readNode (isfd, keynum, addr, Files[isfd]->node, &node);
   if (pIserrno != 0)
      return Return;

   tksz = node.kdesc->k_len + sizeof(RECNUM) + psz;

   if (node.nodeType == LEAF_NODE) {
      for (i = 0; i < node.numElem; i++)
         if ((rc=_pI__keyCmp (&node.nodeArea[i*tksz], key, node.kdesc)) >= 0) {
            if (rc > 0) {
               break;
            } else if (dup) {
               if (Files[isfd]->releaseLevel == 1)
                  rc=pntohl(&node.nodeArea[i*tksz+node.kdesc->k_len])-kprog;
               else
                  rc=kprog-pntohl(&node.nodeArea[i*tksz+node.kdesc->k_len]);
               if (rc == 0) {
                  Return = pntohl(&node.nodeArea[i*tksz+node.kdesc->k_len+psz]);
                  break;
               } else if (rc > 0)
                  break;
            } else {
               Return = pntohl(&node.nodeArea[i*tksz+node.kdesc->k_len+psz]);
               break;
            }
         }
   }
   return Return;
}

static NodeItemDesc *
_pI__next(FILEDESC isfd, short keynum, unsigned char *key,
          ADDR addr, PROG kprog, int dup, ISBOOL equal)
{
   register int i;
   int rc;
   NodeDesc node;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz;

   _pI__readNode (isfd, keynum, addr, Files[isfd]->node, &node);
   if (pIserrno != 0)
      return Return;

   tksz = node.kdesc->k_len + sizeof(RECNUM) + psz;

   if (node.nodeType == LEAF_NODE) {
      for (i = 0; i < node.numElem; i++) {
         rc = _pI__keyCmp (&node.nodeArea[i * tksz], key, node.kdesc);
         if (rc < 0)
            continue;
         else if (rc > 0)
            break;
         else {
            if (dup) {
               if (Files[isfd]->releaseLevel == 1)
                  rc=pntohl(&node.nodeArea[i*tksz+node.kdesc->k_len])-kprog;
               else
                  rc=kprog-pntohl(&node.nodeArea[i*tksz+node.kdesc->k_len]);
               if (rc < 0)
                  continue;
               else if (rc > 0)
                  break;
            }
            if (equal)
               break;
         }
      }
      if (i < node.numElem) {
         getKeyDesc(found,i,(&node));
      } else
         if (node.rightBrot != 0)
            Return = _pI__next(isfd, keynum, key, node.rightBrot,
                               kprog, dup, equal);
   } else
      pIserrno = EBADFILE;
   return Return;
}

static NodeItemDesc *
_pI__prev(FILEDESC isfd, short keynum, unsigned char *key,
          ADDR addr, PROG kprog, int dup, ISBOOL equal)
{
   register int i;
   int rc;
   NodeDesc node;
   static NodeItemDesc found;
   NodeItemDesc * Return = 0;
   int psz = (dup ? sizeof(PROG) : 0);
   int tksz;

   _pI__readNode (isfd, keynum, addr, Files[isfd]->node, &node);
   if (pIserrno != 0)
      return Return;

   tksz = node.kdesc->k_len + sizeof(RECNUM) + psz;

   if (node.nodeType == LEAF_NODE) {
      for (i = node.numElem - 1; i >= 0; i--) {
         rc = _pI__keyCmp (&node.nodeArea[i * tksz], key, node.kdesc);
         if (rc > 0)
            continue;
         else if (rc < 0)
            break;
         else {
            if (dup) {
               if (Files[isfd]->releaseLevel == 1)
                  rc=pntohl(&node.nodeArea[i*tksz+node.kdesc->k_len])-kprog;
               else
                  rc=kprog-pntohl(&node.nodeArea[i*tksz+node.kdesc->k_len]);
               if (rc > 0)
                  continue;
               else if (rc < 0)
                  break;
            }
            if (equal)
               break;
         }
      }
      if (i >= 0) {
         getKeyDesc(found,i,(&node));
      } else
         if (node.leftBrot != 0)
            Return = _pI__prev(isfd, keynum, key, node.leftBrot,
                               kprog, dup, equal);
   } else
      pIserrno = EBADFILE;
   return Return;
}

static Void
_pI__delNode(FILEDESC isfd, ADDR addr, unsigned char *buffer)
{
   Void Return = 0;
   register unsigned char *pnt = buffer;

   *pnt++ = DELETED_NODE;
   putLongInBuffer(pnt, Files[isfd]->firstDeletedNode);
   Files[isfd]->firstDeletedNode = addr;
   indexLseek(isfd, addr);
   writeIndex(isfd, buffer);
   return Return;
}

static Void
_pI__delTree(FILEDESC isfd, ADDR addr, short keynum)
{
   register int i;
   unsigned char *buffer = malloc(Files[isfd]->dictInfo.di_idxsize);
   NodeDesc thisNode;
   Void Return = 0;
   int tksz;
   ADDR nextAddr;

   _pI__readNode (isfd, keynum, addr, buffer, &thisNode);
   if (pIserrno != 0)
      return Return;

   if (thisNode.nodeType == BRANCH_NODE) {
      tksz = thisNode.kdesc->k_len + sizeof(RECNUM);
      for (i = 0; i < thisNode.numElem; i++) {
         nextAddr = pntohl(&thisNode.nodeArea[i*tksz+thisNode.kdesc->k_len]);
         _pI__delTree(isfd, nextAddr, keynum);
      }
   }
   if (thisNode.nodeType == BRANCH_NODE || thisNode.nodeType == LEAF_NODE) {
      _pI__delNode(isfd, addr, buffer);
   } else
      pIserrno = EBADFILE;
   free(buffer);
   return Return;
}

static void
_pI__deleteKeyFromNode (NodeDesc *thisNode, int pos, int tksz, int dup)
{
   char * pnt, *epnt;
   epnt = &thisNode->nodeArea[(thisNode->numElem - 1) * tksz];
   for (pnt = &thisNode->nodeArea[(pos + 1) * tksz]; pnt <= epnt; pnt += tksz)
       memcpy (pnt - tksz, pnt, tksz);
   memset (epnt, 0xFF, thisNode->kdesc->k_len);
   epnt += thisNode->kdesc->k_len;
   if (dup)
      putLongInBuffer(epnt,0L);
   putLongInBuffer(epnt,0);
   thisNode->numElem --;
}

static short
_pI__deleteKey (unsigned char * key, ADDR addr, 
                short keynum, FILEDESC isfd, struct keydesc *kdesc, int dup,
                RECNUM recnum)
{
   short Return = -1;
   NodeDesc thisNode;
   char *buffNode;
   short nextNodePos;
   int i;

   if (addr == 0)
      return Return;
   buffNode = malloc (Files[isfd]->dictInfo.di_idxsize);
   _pI__readNode (isfd, keynum, addr, buffNode, &thisNode);
   if (pIserrno != 0) {
      free (buffNode);
      return Return;
   }
   if (thisNode.nodeType == LEAF_NODE) {
      int psz = (dup ? sizeof(PROG) : 0);
      int tksz = kdesc->k_len + sizeof(RECNUM) + psz;
      for (i = 0; i < thisNode.numElem; i++) {
         if (recnum ==
               pntohl(&thisNode.nodeArea[i*tksz+thisNode.kdesc->k_len+psz])) {
           if (thisNode.numElem == 1 && 
                addr != Files[isfd]->keyDesc[keynum]->k_rootnode) {
               _pI__delNode(isfd, addr, buffNode);
               if (thisNode.rightBrot)
                  _pI__changeRightBrother (thisNode.rightBrot,
                                          thisNode.leftBrot, isfd, LEAF_NODE);
               if (thisNode.leftBrot)
                  _pI__changeLeftBrother(thisNode.leftBrot,
                                          thisNode.rightBrot, isfd, LEAF_NODE);
               Return = 0;
            } else {
               Return = thisNode.numElem;
               _pI__deleteKeyFromNode (&thisNode, i, tksz, dup);
               _pI__writeNode (isfd, buffNode, &thisNode);
            }
            break;
         }
      }
   } else if (thisNode.nodeType == BRANCH_NODE) {
      nextNodePos =_pI__searchGeBranch (&thisNode, key, kdesc);
      do {
         if ((Return = _pI__deleteKey (key, getNumRec(thisNode,nextNodePos),
                                      keynum, isfd, kdesc, dup, recnum)) >= 0 ||
                                      pIserrno != 0) {
            if (pIserrno != 0) {
               ;
            } else if (Return == 0) {
               if (thisNode.numElem == 1) {
                  if (addr == Files[isfd]->keyDesc[keynum]->k_rootnode) {
                     thisNode.nodeType = LEAF_NODE;
                     thisNode.numElem = 0;
                     thisNode.leftBrot = 0;
                     thisNode.rightBrot = 0;
                     _pI__writeNode (isfd, buffNode, &thisNode);
                  } else {
                     _pI__delNode(isfd, addr, buffNode);
                     if (thisNode.rightBrot)
                        _pI__changeRightBrother (thisNode.rightBrot,
                                    thisNode.leftBrot, isfd, BRANCH_NODE);
                     if (thisNode.leftBrot)
                        _pI__changeLeftBrother(thisNode.leftBrot,
                                    thisNode.rightBrot, isfd, BRANCH_NODE);
                     Return = 0;
                  }
               } else if (thisNode.numElem - 1 == nextNodePos) {
                  int tksz = kdesc->k_len + sizeof(RECNUM);
                  _pI__deleteKeyFromNode (&thisNode, nextNodePos, tksz, 0);
                  memset(&thisNode.nodeArea[(thisNode.numElem - 1) * tksz],
                         0xFF, thisNode.kdesc->k_len);
                  _pI__writeNode (isfd, buffNode, &thisNode);
                  Return = thisNode.numElem;
               } else {
                  int tksz = kdesc->k_len + sizeof(RECNUM);
                  _pI__deleteKeyFromNode (&thisNode, nextNodePos, tksz, 0);
                  _pI__writeNode (isfd, buffNode, &thisNode);
                  Return = thisNode.numElem;
               }
            }
         } else {
            int tksz = kdesc->k_len + sizeof(RECNUM);
            nextNodePos++;
            if (nextNodePos < thisNode.numElem) {
               if (_pI__keyCmp (&thisNode.nodeArea[(nextNodePos - 1) * tksz],
                                key, thisNode.kdesc) <= 0)
                  continue;
               else
                  pIserrno = EBADFILE;
            }
         }
         break;
      } while (1);

   } else
      pIserrno = EBADFILE;
   free (buffNode);
   return Return;
}

#ifdef AUDIT_TRAIL

# define auditTrail(f,op,rec) ((Files[f]->auditFd>=0)?\
                                _pI__writeAudit(f,op,rec):0)
static int
_pI__writeAudit (FILEDESC isfd, char op, char *rec)
{
   static unsigned short procid = 0;
   static short userid = -1;
   unsigned char ah[sizeof (struct audhead)];
   unsigned char *pnt = ah;

   if (procid == 0)
      procid = getpid();
   if (userid == -1)
      userid = getuid();
   if (pIserrno != 0) {
      *pnt++ = toupper(op);
      *pnt++ = pIserrno;
   } else {
      *pnt++ = op;
      *pnt++ = op;
   }
   putLongInBuffer(pnt, time(0));
   putShortInBuffer(pnt, procid);
   putShortInBuffer(pnt, userid);
   putLongInBuffer(pnt, pIsrecnum);
   write (Files[isfd]->auditFd, ah, sizeof(struct audhead));
   write (Files[isfd]->auditFd, rec, Files[isfd]->dictInfo.di_recsize);
# if defined(HAS_FDATASYNC)
   fdatasync (Files[isfd]->auditFd);
# elif defined(HAS_FSYNC)
   fsync (Files[isfd]->auditFd);
# endif
   return 0;
}
#endif

int ISAM_API
pIsrename(char * oldpath, char * newpath)
{
   char * oldName;
   char * newName;
   int Return = -1;

   pIserrno = 0;

   oldName = malloc (strlen (oldpath) + sizeof(INDEX_EXT) + sizeof(DATA_EXT));
   newName = malloc (strlen (newpath) + sizeof(INDEX_EXT) + sizeof(DATA_EXT));
   sprintf (oldName, "%s%s", oldpath, INDEX_EXT);
   sprintf (newName, "%s%s", newpath, INDEX_EXT);

   if (rename (oldName, newName) < 0 ) { 
      pIserrno = errno; 
      pIserrio = errno;
   } else {
      sprintf (oldName, "%s%s", oldpath, DATA_EXT);
      sprintf (newName, "%s%s", newpath, DATA_EXT);
      if (rename (oldName, newName) < 0 ) { 
         pIserrno = errno; 
         pIserrio = errno;
         sprintf (oldName, "%s%s", oldpath, INDEX_EXT);
         sprintf (newName, "%s%s", newpath, INDEX_EXT);
         rename (newName, oldName);
      } else
         Return = 0;
   }
   free (oldName);
   free (newName);
   return Return;
}

int ISAM_API
pIserase(char * filename)
{
   char * fileNameErase;
   int len;
   int Return = -1;

   pIserrno = 0;

   len = strlen (filename);
   fileNameErase = malloc (len + sizeof(INDEX_EXT) + sizeof(DATA_EXT));
   sprintf (fileNameErase, "%s%s", filename, INDEX_EXT);
   if (unlink (fileNameErase) < 0 ) { 
      pIserrno = errno; 
      pIserrio = errno;
      return Return;
   }
   sprintf (fileNameErase, "%s%s", filename, DATA_EXT);
   if (unlink (fileNameErase) < 0 ) { 
      pIserrno = errno; 
      pIserrio = errno;
   }
   free (fileNameErase);
   Return = 0;
   return Return;
}

FILEDESC ISAM_API
pIsbuildNodeSize (char * filename, int recordlength,
         struct keydesc *keyd, int mode, int headersize, int nodesize)
{
   FILEDESC Return = FILEDESC_ERROR;
   FILEDESC isfd = FILEDESC_ERROR;
   short i;

   pIserrno = 0;
   pIserrio = 0;
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsbuild        file=%s, mode=%d\n",filename,mode);
# endif
   checkMode(mode);
   checkKeyDesc(keyd);
   checkFileName(filename);

   keyd->k_rootnode = headersize;

   keyd->k_len = 0;
   for (i = 0; i < keyd->k_nparts; i++) {
      checkKeyPart(keyd->k_part[i], recordlength);
      if (pIserrno == 0)
         keyd->k_len += keyd->k_part[i].kp_leng;
      else
         RETURN
   }
   if (keyd->k_len > MAXKEYSIZE){
      pIserrno = EBADKEY;
      RETURN
   }

   if ((isfd =_pI__open(filename, _pI__mapOpenMode(ISINOUT)|O_CREAT|O_EXCL))<0)
      RETURN
   if (getLockMode(mode) == ISEXCLLOCK) {
      _pI__fileExLock(isfd);
      if (pIserrno != 0) {
         _pI__freeFile (isfd);
         RETURN;
      }
   } else {
      _pI__testFileLock(isfd);
      if (pIserrno != 0) {
         _pI__freeFile (isfd);
         RETURN;
      }
   }
   Files[isfd]->openMode = mode;

   Files[isfd]->releaseLevel = RELEASE;
   Files[isfd]->dictInfo.di_nkeys = 1;
   Files[isfd]->dictInfo.di_recsize = recordlength;
   Files[isfd]->dictInfo.di_idxsize = nodesize;
   Files[isfd]->dictInfo.di_nrecords = 0;

   Files[isfd]->firstFreeNode = headersize + nodesize;
   Files[isfd]->headerSize = headersize;
   Files[isfd]->firstAddKeyNode = 0L;
   Files[isfd]->firstDeletedNode = 0L;
   Files[isfd]->firstDelRecNode = 0L;

   _pI__allocFile (isfd, filename);
  

   memcpy ((char *) Files[isfd]->keyDesc[0], (char *) keyd,
                                               sizeof(struct keydesc));
   _pI__writeHeader (isfd);
   if (pIserrno != 0)
      RETURN

   indexLseek (isfd, Files[isfd]->keyDesc[0]->k_rootnode);
   memset (Files[isfd]->node, 0, nodesize);
   *Files[isfd]->node = LEAF_NODE;
   writeIndex (isfd,Files[isfd]->node);
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsbuild        isfd=%d, pIserrno=%d\n", isfd, pIserrno);
# endif
   Return = isfd;
#ifdef TRANSACTION
   if (beginWork && isOpenTrans(Files[isfd]->openMode)) {
      Return = _pI__transaction (TNX_FILE_OPEN, isfd, 0, filename, 0, 0, 0);
      if (Return == 0)
         Return = isfd;
   } else {
      Files[isfd]->openMode &= ~ISTRANS;
   }
#endif
   RETURN
}

FILEDESC ISAM_API
pIsbuild (char * filename, int recordlength,
         struct keydesc *keyd, int mode)
{
   return pIsbuildNodeSize (filename, recordlength, keyd, mode,
                            HEADERSIZE, MAXNODESIZE);
}

int ISAM_API
pIsopen (char * filename, int mode)
{
   FILEDESC isfd;
   FILEDESC Return = FILEDESC_ERROR;
   unsigned char *pnt;
   static unsigned char header[FIRSTKEYDISP];
   register short i, j;
   short reminder;
   short firstNodeNKeys;
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsopen        file=%s, mode=%d\n",filename,mode);
# endif

   pIserrno = 0;
   pIserrio = 0;
   checkMode(mode);
   checkFileName(filename);
# ifdef TRANSACTION
   if (beginWork && isOpenTrans(mode)) {
      for (i = 0; i < nFileToClose; i++) {
         isfd = fileToClose[i];
         if (isfd >= 0 && Files[isfd] != 0 && Files[isfd]->openMode == mode) {
            for (j = 0;
                 filename[j] && filename[j] == Files[isfd]->dataName[j];
                 j++)
               ;
            if (strcmp (&(Files[isfd]->dataName[j]), DATA_EXT) == 0) {
               Files[isfd]->currIndex = 0;
               setNodeItemDesc(Files[isfd]->curr,0,0,0,0,0,0);
               setNodeItemDesc(Files[isfd]->next,0,0,0,0,0,0);
               Return = fileToClose[i];
               fileToClose[i] = -1;
               return Return;
            }
         }
      }
   }
# endif
   if ((isfd =_pI__open (filename, _pI__mapOpenMode(mode))) < 0)
      RETURN
   if (getLockMode(mode) == ISEXCLLOCK) {
      _pI__fileExLock(isfd);
      if (pIserrno != 0) {
         _pI__freeFile (isfd);
         RETURN;
      }
   } else if (getOpenMode(mode) != ISINPUT) {
      _pI__testFileLock(isfd);
      if (pIserrno != 0) {
         _pI__freeFile (isfd);
         RETURN;
      }
   }
   Files[isfd]->openMode = mode;
   _pI__headerLock (isfd, ISFALSE);
   if (read (Files[isfd]->fdIndex, header, FIRSTKEYDISP) < FIRSTKEYDISP) {
      pIserrio = errno;
      pIserrno = EBADFILE;
      _pI__freeFile (isfd);
      RETURN 
   }
      
   pnt = header;

/* 0-5 Signature */
   
   if (memcmp(pnt, SIGN, 6) != 0) {
      pIserrno = EBADFILE;
      _pI__freeFile (isfd);
      RETURN
   }
   pnt += 6;
/* 6-7 Release */
   getShortFromBuffer(Files[isfd]->releaseLevel,pnt);
   if (Files[isfd]->releaseLevel < 0 ||
       Files[isfd]->releaseLevel > 1)  {
      pIserrno = EBADFILE;
      _pI__freeFile (isfd);
      RETURN
   }

/* 8-11 first free node */
   getLongFromBuffer(Files[isfd]->firstFreeNode, pnt);

/* 12-13 number of keys */
   getShortFromBuffer(Files[isfd]->dictInfo.di_nkeys, pnt);
/* 14-15 recsize  */
   getShortFromBuffer(Files[isfd]->dictInfo.di_recsize,pnt);
/* 16-17 index record size  */
   getShortFromBuffer(Files[isfd]->dictInfo.di_idxsize,pnt);
/* 18-21 number of record */
   getLongFromBuffer(Files[isfd]->dictInfo.di_nrecords,pnt);
/* 22-23 header dimension */
   getShortFromBuffer(Files[isfd]->headerSize, pnt);
/* 24-27 first deleted node */
   getLongFromBuffer(Files[isfd]->firstDeletedNode, pnt);
/* 28-31 first deleted record node */
   getLongFromBuffer(Files[isfd]->firstDelRecNode, pnt);

   _pI__allocFile (isfd, filename);

   reminder = Files[isfd]->headerSize - FIRSTKEYDISP;

   if (read (Files[isfd]->fdIndex, headerArea, reminder) < reminder) {
      pIserrio = errno;
      pIserrno = EBADFILE;
      _pI__freeFile (isfd);
      RETURN
   }

/* <last four bytes> first additional key node */
   firstNodeNKeys = Files[isfd]->dictInfo.di_nkeys;
   pnt = headerArea + reminder - sizeof(ADDR);
   getLongFromBuffer(Files[isfd]->firstAddKeyNode, pnt);
   if (Files[isfd]->dictInfo.di_nkeys * HEADERKEYSIZE >
       Files[isfd]->headerSize - FIRSTKEYDISP - sizeof(ADDR)) {
      ADDR newNode = Files[isfd]->firstAddKeyNode;
      unsigned short endNode = Files[isfd]->dictInfo.di_idxsize - sizeof(ADDR);
      unsigned short offs = endNode;
      i = (Files[isfd]->headerSize - FIRSTKEYDISP - sizeof(ADDR))/HEADERKEYSIZE;
      firstNodeNKeys = i;
      for ( ; i < Files[isfd]->dictInfo.di_nkeys; i++){
         if ((offs += HEADERKEYSIZE) > endNode) {
            if (newNode == 0) {
               pIserrno = EBADFILE;
               _pI__freeFile (isfd);
               return Return;
            }
            indexLseek (isfd, newNode);
            readIndex (isfd, Files[isfd]->node);
            pnt = &Files[isfd]->node[endNode];
            getLongFromBuffer (newNode, pnt);
            pnt = Files[isfd]->node;
            if (*pnt++ != KEY_NODE) {
               pIserrno = EBADFILE;
               _pI__freeFile (isfd);
               return Return;
            } 
            offs =  HEADERKEYSIZE + 1;
         }
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_flags, pnt);
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_nparts, pnt);
         for (j = 0; j < Files[isfd]->keyDesc[i]->k_nparts; j++) {
            getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_start, pnt);
            getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_leng, pnt);
            getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_type, pnt);
         }
         pnt += sizeof(short) * 3 * (NPARTS - j);
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_len,pnt);
         getLongFromBuffer(Files[isfd]->keyDesc[i]->k_rootnode,pnt);
      }
   }
  
   pnt = headerArea;
   for (i = 0; i < firstNodeNKeys; i++) {
      getShortFromBuffer(Files[isfd]->keyDesc[i]->k_flags, pnt);
      getShortFromBuffer(Files[isfd]->keyDesc[i]->k_nparts, pnt);
      for (j = 0; j < Files[isfd]->keyDesc[i]->k_nparts; j++) {
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_start, pnt);
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_leng, pnt);
         getShortFromBuffer(Files[isfd]->keyDesc[i]->k_part[j].kp_type, pnt);
      }
      pnt += sizeof(short) * 3 * (NPARTS - j);
      getShortFromBuffer(Files[isfd]->keyDesc[i]->k_len,pnt);
      getLongFromBuffer(Files[isfd]->keyDesc[i]->k_rootnode,pnt);
   }

# ifdef ISAMDEBUG
   fprintf (stderr, "pIsopen        isfd=%d, pIserrno=%d\n", isfd, pIserrno);
# endif
   Return = isfd;
#ifdef TRANSACTION
   if (beginWork && isOpenTrans(Files[isfd]->openMode)) {
      Return = _pI__transaction (TNX_FILE_OPEN, isfd, 0, filename, 0, 0, 0);
      if (Return == 0)
         Return = isfd;
   } else {
      Files[isfd]->openMode &= ~ISTRANS;
   }
#endif
   RETURN
}

int ISAM_API
pIsindexinfo (FILEDESC isfd , void *buffer, int num)
{
   int Return = -1;

   pIserrno = 0;

   checkIsOpen(isfd);
   if (num < 0 || num > Files[isfd]->dictInfo.di_nkeys) {
      pIserrno = EBADARG;
      RETURN
   }
   _pI__readHeader (isfd, ISFALSE);
   if (pIserrno != 0)
       RETURN
   if (num == 0) {
      memcpy ((unsigned char *) buffer, 
              (unsigned char *)(&Files[isfd]->dictInfo),
              sizeof (struct dictinfo));
      Return = 0;
   } else {
      memcpy ((unsigned char *) buffer, 
              (unsigned char *)(Files[isfd]->keyDesc[num - 1]),
              sizeof (struct keydesc));
      Return = 0;
   }
# ifdef ISAMDEBUG
   fprintf (stderr, "isindexinf        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

int ISAM_API
pIswrite (FILEDESC isfd, char * record)
{
   register short i;
   RECNUM numrec;
   NewNodes *kaa;
   ADDR newRoot;
   NodeItemDesc *found;
   int Return = -1;

# ifdef ISAMDEBUG
   fprintf (stderr, "pIswrite        file=%s\n",Files[isfd]->dataName);
# endif
   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
       RETURN
   for (i = 0; i < Files[isfd]->dictInfo.di_nkeys; i++) {
      if (Files[isfd]->keyDesc[i]->k_nparts > 0) {
         _pI__buildKey (isfd, i, (unsigned char *)record, Files[isfd]->keySup[i]->bufKey);

         if (!isKeyDup(isfd,i)) {
            found = _pI__findKey (Files[isfd]->keySup[i]->bufKey,
                       Files[isfd]->keyDesc[i]->k_rootnode, i, isfd,
                       Files[isfd]->keyDesc[i], ISEQUAL, isKeyDup(isfd,i));
            if (found != 0) {
               pIserrno = EDUPL;
           RETURN;
            }
         }
      }
   }
   numrec = _pI__getRecNum(isfd);
   _pI__recordLock (isfd, numrec,ISFALSE);
   if (pIserrno != 0) {
      _pI__resetGetRecNum(isfd, numrec);
      RETURN;
   }
   for (i = 0; i < Files[isfd]->dictInfo.di_nkeys; i++) {
      if (Files[isfd]->keyDesc[i]->k_nparts > 0) {
         kaa = _pI__insertKey (Files[isfd]->keySup[i]->bufKey,
                       Files[isfd]->keyDesc[i]->k_rootnode, i, isfd, numrec);
         if (pIserrno != 0) {
            _pI__recordUnlock (isfd, numrec);
            _pI__resetGetRecNum(isfd, numrec);
#ifdef AUDIT_TRAIL
             auditTrail(isfd,'a',record);
#endif
            RETURN
         } else if (kaa != 0 ) {
            if ((newRoot = _pI__newRoot (kaa, isfd, i)) != 0)
               Files[isfd]->keyDesc[i]->k_rootnode = newRoot;
            else {
               _pI__recordUnlock (isfd, numrec);
               _pI__resetGetRecNum(isfd, numrec);
#ifdef AUDIT_TRAIL
               auditTrail(isfd,'a',record);
#endif
               RETURN
            }
         }
      }
   }
   _pI__writeHeader (isfd);
   if (pIserrno == 0) {
      dataLseek(isfd, numrec);
      writeData (isfd, (unsigned char *) record);
      pIsrecnum = numrec;
      Return = 0;
#ifdef TRANSACTION
      if (beginWork && isOpenTrans(Files[isfd]->openMode))
         Return = _pI__transaction (TNX_INSERT, isfd, pIsrecnum, 0, 0,
                                    record, Files[isfd]->dictInfo.di_recsize);
      else
#endif
         _pI__recordUnlock (isfd, numrec);
   } else {
      _pI__resetGetRecNum(isfd, numrec);
      _pI__recordUnlock (isfd, numrec);
   }
#ifdef AUDIT_TRAIL
   auditTrail(isfd,'a',record);
#endif
# ifdef ISAMDEBUG
   fprintf (stderr, "pIswrite        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

int ISAM_API
pIsreplace (FILEDESC isfd, char * record)
{
   register short i;
   NodeItemDesc *found = 0;
   int Return = -1;

# ifdef ISAMDEBUG
   fprintf (stderr, "pIsreplace      file=%s\n",Files[isfd]->dataName);
# endif
   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
       RETURN
   for (i = 0; i < Files[isfd]->dictInfo.di_nkeys; i++) {
      if (Files[isfd]->keyDesc[i]->k_nparts > 0) {
         if (!isKeyDup(isfd,i)) {
            _pI__buildKey (isfd, i, (unsigned char *)record, Files[isfd]->keySup[i]->bufKey);
            found = _pI__findKey (Files[isfd]->keySup[i]->bufKey,
                       Files[isfd]->keyDesc[i]->k_rootnode, i, isfd,
                       Files[isfd]->keyDesc[i], ISEQUAL, isKeyDup(isfd,i));
            if (found != 0) {
               break;
            }
         }
      }
   }
   if (found != 0)
      Return = pIsrewrec (isfd, found->numRec, record);
   else
      Return = pIswrite (isfd, record);
   RETURN
}

int ISAM_API
pIsaddindex (FILEDESC isfd, struct keydesc *keydesc)
{
   short j;
   register int i;
   int Return = -1;
   int recsize;
   RECNUM recnum;
   unsigned char *record;
   NewNodes *kaa;
   ADDR newRoot;

   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
       RETURN

   checkKeyDesc(keydesc);

   keydesc->k_len = 0;
   for (i = 0; i < keydesc->k_nparts; i++) {
      checkKeyPart(keydesc->k_part[i], Files[isfd]->dictInfo.di_recsize);
      if (pIserrno == 0)
         keydesc->k_len += keydesc->k_part[i].kp_leng;
      else
         RETURN
   }
   if (keydesc->k_len > MAXKEYSIZE){
      pIserrno = EBADKEY;
      RETURN
   }  

   for (j = 0; j < Files[isfd]->dictInfo.di_nkeys; j++)
      if (keydesc->k_nparts > 0 && keydesc->k_nparts == Files[isfd]->keyDesc[j]->k_nparts ) {
         pIserrno = EKEXISTS;
         for (i = 0; i < keydesc->k_nparts; i++) {
            if (keydesc->k_part[i].kp_start != 
                 Files[isfd]->keyDesc[j]->k_part[i].kp_start ||
                 keydesc->k_part[i].kp_leng != 
                 Files[isfd]->keyDesc[j]->k_part[i].kp_leng)
               pIserrno = 0;
         }
         if (pIserrno != 0)
            RETURN
      }

   j = Files[isfd]->dictInfo.di_nkeys++;

   _pI__allocKey (isfd, j, Files[isfd]->dictInfo.di_nkeys);

   memcpy ((char *) Files[isfd]->keyDesc[j], (char *) keydesc,
                           sizeof(struct keydesc));

   Files[isfd]->keyDesc[j]->k_rootnode = _pI__getFreeNode(isfd);

   _pI__writeHeader (isfd);

   if (pIserrno != 0) {
#ifdef AUDIT_TRAIL
      auditTrail(isfd,'i',Files[isfd]->record);
#endif
      RETURN
   }
   indexLseek (isfd, Files[isfd]->keyDesc[j]->k_rootnode);
   memset (Files[isfd]->node, 0, Files[isfd]->dictInfo.di_idxsize);
   *Files[isfd]->node = LEAF_NODE;
   writeIndex (isfd,Files[isfd]->node);

   if (pIserrno != 0) {
#ifdef AUDIT_TRAIL
      auditTrail(isfd,'i',Files[isfd]->record);
#endif
      RETURN
   }
   dataLseek(isfd,1);
   recsize = Files[isfd]->dictInfo.di_recsize + 1;
   record = Files[isfd]->record;
   if (Files[isfd]->keyDesc[j]->k_nparts > 0) {
      for (recnum=1;read(Files[isfd]->fdData,record,recsize) == recsize;
           recnum++) {
         if (record[Files[isfd]->dictInfo.di_recsize] == '\n') {
            _pI__buildKey (isfd, j, record, Files[isfd]->keySup[j]->bufKey);
            kaa = _pI__insertKey (Files[isfd]->keySup[j]->bufKey,
                          Files[isfd]->keyDesc[j]->k_rootnode, j, isfd, recnum);
            if (pIserrno != 0)
               break;
            else if (kaa != 0 ) {
               if ((newRoot = _pI__newRoot (kaa, isfd, j)) != 0)
                  Files[isfd]->keyDesc[j]->k_rootnode = newRoot;
               else
                  break;
            }
         }
      }
   }
   if (pIserrno == 0) {
      _pI__writeHeader (isfd);
      Return = 0;
   } else {
      int saveIserrno = pIserrno;
      pIsdelindex (isfd, keydesc);
      pIserrno = saveIserrno;
   }
#ifdef AUDIT_TRAIL
   auditTrail(isfd,'i',Files[isfd]->record);
#endif
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsaddindex        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

int ISAM_API
pIsdelindex (FILEDESC isfd, struct keydesc *keydesc)
{
   short j;
   register short i;
   int Return = -1;
   struct keydesc *keyDesc;
   struct keysup *keySup;

   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
       RETURN

   for (j = 0; j < Files[isfd]->dictInfo.di_nkeys; j++)
      if (keydesc->k_nparts == Files[isfd]->keyDesc[j]->k_nparts ) {
         for (i = 0; i < keydesc->k_nparts; i++) {
            if (keydesc->k_part[i].kp_start != 
                 Files[isfd]->keyDesc[j]->k_part[i].kp_start ||
                 keydesc->k_part[i].kp_leng != 
                 Files[isfd]->keyDesc[j]->k_part[i].kp_leng)
               break;
         }
         if (i == keydesc->k_nparts)
            break;
      }
   if (j == 0) {
      pIserrno = EPRIMKEY;
      RETURN
   }

   if (j == Files[isfd]->dictInfo.di_nkeys) {
      pIserrno = EBADKEY;
      RETURN
   }
   _pI__delTree (isfd, Files[isfd]->keyDesc[j]->k_rootnode, j);
   if (pIserrno != 0)
       RETURN

   keyDesc = Files[isfd]->keyDesc[j];
   keySup = Files[isfd]->keySup[j];

   for (i = j + 1; i < Files[isfd]->dictInfo.di_nkeys; i++, j++) {
      Files[isfd]->keyDesc[j]=Files[isfd]->keyDesc[i];
      Files[isfd]->keySup[j] = Files[isfd]->keySup[i];
   }
   Files[isfd]->keyDesc[j] = keyDesc ;
   Files[isfd]->keySup[j] = keySup ;
   Files[isfd]->keyDesc[j]->k_nparts = 0;
   Files[isfd]->dictInfo.di_nkeys--; 
   _pI__writeHeader(isfd);
#ifdef AUDIT_TRAIL
   auditTrail(isfd,'x',Files[isfd]->record);
#endif
   if (pIserrno == 0)
      Return = 0;

# ifdef ISAMDEBUG
   fprintf (stderr, "pIsdelindex        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

int ISAM_API
pIslock(FILEDESC isfd)
{
   int Return = -1;
   pIserrno = 0;

   checkIsOpen(isfd);
   if (getLockMode(Files[isfd]->openMode) == ISMANULOCK)
      _pI__fileLock(isfd);
   else
      pIserrno = EBADOPENMODE;

   if (pIserrno == 0)
      Return = 0;
   RETURN
}

int ISAM_API
pIsunlock(FILEDESC isfd)
{
   int Return = -1;
   pIserrno = 0;

   checkIsOpen(isfd);
#ifdef TRANSACTION
   if (beginWork && isOpenTrans(Files[isfd]->openMode)) {
      Return = 0;
   } else
#endif
   if (getLockMode(Files[isfd]->openMode) == ISMANULOCK)
      _pI__fileUnlock(isfd);
   else
      pIserrno = EBADOPENMODE;

   Return = 0;
   RETURN
}

int ISAM_API
pIsrelease(FILEDESC isfd)
{
   int Return = -1;
   pIserrno = 0;

   checkIsOpen(isfd);
#ifdef TRANSACTION
   if (beginWork && isOpenTrans(Files[isfd]->openMode)) {
      Return = 0;
   } else
#endif
   _pI__allRecordUnlock(isfd);

   Return = 0;
   RETURN
}

int ISAM_API
pIsclose (FILEDESC isfd)
{
   short Return = -1;
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsclose        file=%s\n",Files[isfd]->dataName);
# endif

   pIserrno = 0;

   checkIsOpen(isfd);
# ifdef AUDIT_TRAIL
   pIsaudit (isfd, 0, AUDSTOP);
# endif
      Return = 0;
#ifdef TRANSACTION
   if (beginWork && isOpenTrans(Files[isfd]->openMode)) {
      int i;
      Return = _pI__transaction (TNX_FILE_CLOSE, isfd, 0, 0, 0, 0, 0);

      for (i = 0; i < nFileToClose; i++) {
         if (fileToClose[i] == -1) {
            fileToClose[i] = isfd;
            break;
         }
      }
      if (i == nFileToClose) {
         fileToClose[i] = isfd;
         nFileToClose++;
      }
   } else
#endif

   _pI__freeFile (isfd);

# ifdef ISAMDEBUG
   fprintf (stderr, "pIsclose        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

int ISAM_API
pIsstart (FILEDESC isfd, struct keydesc * keydesc, int length,
                        char * record, int mode)
{
   register short i, j;
   int Return = -1;
   NodeItemDesc *found;
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsstart        file=%s, mode=%d\n",Files[isfd]->dataName,mode);
# endif

   pIserrno = 0;
   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISOUTPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISFALSE);
   if (pIserrno != 0)
       RETURN

   Files[isfd]->curr.numRec = 0;

   if (keydesc->k_nparts == 0) {
      Files[isfd]->currIndex = -1;
      switch (mode) {
      case ISFIRST:
         if (Files[isfd]->dictInfo.di_nrecords > 0) {
            Files[isfd]->next.numRec = 1;
            pIsrecnum = Files[isfd]->next.numRec;
            Return = 0;
         } else {
            pIserrno = ENOREC;
         }
         break;
      case ISLAST:
         if (Files[isfd]->dictInfo.di_nrecords > 0) {
            Files[isfd]->next.numRec = Files[isfd]->dictInfo.di_nrecords;
            pIsrecnum = Files[isfd]->next.numRec;
            Return = 0;
         } else {
            pIserrno = ENOREC;
         }
         break;
      case ISEQUAL:
         if (pIsrecnum > 0 && pIsrecnum <= Files[isfd]->dictInfo.di_nrecords) {
             Files[isfd]->next.numRec = pIsrecnum;
             Return = 0;
         } else
            pIserrno = ENOREC;
         break;
      default:
         pIserrno = EBADARG;
         RETURN
      }
      RETURN
   }

   for (i = 0; i < Files[isfd]->dictInfo.di_nkeys; i++)
      if (keydesc->k_nparts == Files[isfd]->keyDesc[i]->k_nparts) {
         for (j = 0; j < keydesc->k_nparts; j++)
            if (keydesc->k_part[j].kp_start !=
                 Files[isfd]->keyDesc[i]->k_part[j].kp_start ||
                 keydesc->k_part[j].kp_leng !=
                 Files[isfd]->keyDesc[i]->k_part[j].kp_leng)
               break;
            if (j == keydesc->k_nparts)
               break;
      }
   if (i == Files[isfd]->dictInfo.di_nkeys) {
      pIserrno = EBADKEY;
      RETURN
   }

   if (mode == ISFIRST) {
      memset (Files[isfd]->keySup[i]->bufKey,0,Files[isfd]->keyDesc[i]->k_len);
      length = Files[isfd]->keyDesc[i]->k_len;
   } else if (mode == ISLAST) {
      memset(Files[isfd]->keySup[i]->bufKey,0xFF,
             Files[isfd]->keyDesc[i]->k_len);
      length = Files[isfd]->keyDesc[i]->k_len;
   } else {
      _pI__buildKey (isfd, i, (unsigned char *)record, Files[isfd]->keySup[i]->bufKey);
      if (length <= 0 || length > Files[isfd]->keyDesc[i]->k_len)
         length = Files[isfd]->keyDesc[i]->k_len;
   }

   Files[isfd]->currIndex = i;
   found = _pI__findKey (Files[isfd]->keySup[i]->bufKey,
                         Files[isfd]->keyDesc[i]->k_rootnode, i,
             isfd, Files[isfd]->keyDesc[i], mode, isKeyDup(isfd,i));
   if (found != 0) {
      copyStruct(Files[isfd]->next, *found);
      pIsrecnum = found->numRec;
      if (mode == ISLAST || mode == ISLESS || mode == ISLTEQ)
         Files[isfd]->curr.numRec = MAXRECNUM;
      Return = 0;
   } else if (pIserrno == 0)
      pIserrno = ENOREC;
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsstart        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

static int
_pI__read (FILEDESC isfd, char *record, int mode)
{
   int Return = -1;
   unsigned char flagcan = 0;
   NodeItemDesc * found;

   pIserrno = 0;
   pIsrecnum = 0;

   _pI__readHeader (isfd, ISFALSE);
   if (pIserrno != 0)
       RETURN

   if (Files[isfd]->currIndex == -1 ||
       Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_nparts == 0) {
      Files[isfd]->currIndex = -1;
      switch (getReadMode(mode)) {
      case ISCURR:
         if (Files[isfd]->curr.numRec == 0)
             Files[isfd]->curr.numRec = Files[isfd]->next.numRec;
         if (Files[isfd]->curr.numRec > Files[isfd]->dictInfo.di_nrecords) {
            pIserrno = EENDFILE;
            RETURN
         }
         if (Files[isfd]->curr.numRec == 0)
            Files[isfd]->curr.numRec = 1;

         while (flagcan == 0 &&
                Files[isfd]->curr.numRec <= Files[isfd]->dictInfo.di_nrecords) {
            lockData(isfd, mode, Files[isfd]->curr.numRec);
            readData(isfd,(unsigned char *) record,flagcan);
            if (flagcan == '\n') {
               pIsrecnum = Files[isfd]->curr.numRec;
               Files[isfd]->next.numRec = Files[isfd]->curr.numRec + 1;
            } else if (flagcan == 0) {
               unlockData(isfd, mode, Files[isfd]->curr.numRec);
               Files[isfd]->curr.numRec++;
            }
         }
         if (flagcan != '\n') {
            pIserrno = EENDFILE;
         } else
            Return = 0;
         break;
      case ISNEXT:
         if (Files[isfd]->next.numRec > Files[isfd]->dictInfo.di_nrecords) {
            pIserrno = EENDFILE;
            RETURN
         }
         if (Files[isfd]->next.numRec == 0)
            Files[isfd]->next.numRec = 1;
         while (flagcan == 0 &&
                Files[isfd]->next.numRec <= Files[isfd]->dictInfo.di_nrecords) {
            lockData(isfd, mode, Files[isfd]->next.numRec);
            readData(isfd,(unsigned char *) record,flagcan);
            if (flagcan == '\n') {
               pIsrecnum = Files[isfd]->next.numRec;
               Files[isfd]->curr.numRec = Files[isfd]->next.numRec;
               Files[isfd]->next.numRec++;
            } else if (flagcan == 0) {
               unlockData(isfd, mode, Files[isfd]->next.numRec);
               Files[isfd]->next.numRec++;
            }
         }
         if (flagcan != '\n') {
            pIserrno = EENDFILE;
         } else
            Return = 0;
         break;
      case ISPREV:
         if (Files[isfd]->curr.numRec == 0)
             Files[isfd]->curr.numRec = Files[isfd]->next.numRec;
         if (Files[isfd]->curr.numRec > Files[isfd]->dictInfo.di_nrecords)
            Files[isfd]->curr.numRec = Files[isfd]->dictInfo.di_nrecords;
         else {
            Files[isfd]->next.numRec = Files[isfd]->curr.numRec;
            Files[isfd]->curr.numRec--;
         }
         if (Files[isfd]->curr.numRec == 0) {
            pIserrno = EENDFILE;
            RETURN
         }
         while (flagcan == 0 &&
                Files[isfd]->curr.numRec > 0) {
            lockData(isfd, mode, Files[isfd]->curr.numRec);
            readData(isfd,(unsigned char *) record,flagcan);
            if (flagcan == '\n') {
               pIsrecnum = Files[isfd]->curr.numRec;
            } else if (flagcan == 0) {
               unlockData(isfd, mode, Files[isfd]->curr.numRec);
               Files[isfd]->curr.numRec--;
            }
         }
         if (flagcan != '\n') {
            pIserrno = EENDFILE;
         } else
            Return = 0;
         break;
      case ISFIRST:
         Files[isfd]->next.numRec = 1;
         while (flagcan == 0 &&
                Files[isfd]->next.numRec <= Files[isfd]->dictInfo.di_nrecords) {
            lockData(isfd, mode, Files[isfd]->next.numRec);
            readData(isfd,(unsigned char *) record,flagcan);
            if (flagcan == '\0') {
               unlockData(isfd, mode, Files[isfd]->next.numRec);
               Files[isfd]->next.numRec++;
            }
         }
         if (flagcan != '\n')
            pIserrno = EENDFILE;
         else {
            pIsrecnum = Files[isfd]->next.numRec;
            Files[isfd]->curr.numRec = Files[isfd]->next.numRec;
            Files[isfd]->next.numRec++;
            Return = 0;
         }
         break;
      case ISLAST:
         Files[isfd]->next.numRec = Files[isfd]->dictInfo.di_nrecords;
         while (flagcan == 0 &&
                Files[isfd]->next.numRec > 0) {
            lockData(isfd, mode, Files[isfd]->next.numRec);
            readData(isfd,(unsigned char *) record,flagcan);
            if (flagcan == '\0') {
               unlockData(isfd, mode, Files[isfd]->next.numRec);
               Files[isfd]->next.numRec--;
            }
         }
         if (flagcan != '\n')
            pIserrno = EENDFILE;
         else {
            pIsrecnum = Files[isfd]->next.numRec;
            Files[isfd]->curr.numRec = Files[isfd]->next.numRec;
            Files[isfd]->next.numRec++;
            Return = 0;
         }
         break;
      default:
         pIserrno = EBADARG;
         RETURN
      }
   } else {
      switch (getReadMode(mode)) {
      case ISCURR:
         if (Files[isfd]->next.numRec == 0) {
            pIsstart (isfd, Files[isfd]->keyDesc[Files[isfd]->currIndex], 0,
                          record, ISFIRST);
            if (pIserrno == 0) {
               Return = _pI__read (isfd, record, mode);
               if (pIserrno != 0)
                  Files[isfd]->next.numRec = 0;
            }
         } else {
            if (Files[isfd]->curr.numRec == 0) {
               copyStruct(Files[isfd]->curr,Files[isfd]->next);
            }
            if (Files[isfd]->curr.numRec > Files[isfd]->dictInfo.di_nrecords ||
                Files[isfd]->curr.numRec == 0) {
               pIserrno = EENDFILE;
               RETURN
            }
            if ((Files[isfd]->curr.numRec = _pI__verifyCurr(isfd,
                                      Files[isfd]->currIndex,
                                      Files[isfd]->curr.keyVal,
                                      Files[isfd]->curr.nodeAddr,
                                      Files[isfd]->curr.keyProg,
                                      isKeyDup(isfd,Files[isfd]->currIndex)))) {
               lockData(isfd, mode, Files[isfd]->curr.numRec);
               readData(isfd,(unsigned char *) record,flagcan);
               checkBadFile(flagcan);
            } else {
               found = _pI__findKey (Files[isfd]->curr.keyVal,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_rootnode,
                       Files[isfd]->currIndex,
                       isfd,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex], 
                       ISGTEQ,
                       isKeyDup(isfd,Files[isfd]->currIndex));
               if (found != 0)
                  found = _pI__next(isfd,
                                    Files[isfd]->currIndex,
                                    Files[isfd]->curr.keyVal,
                                    found->nodeAddr,
                                    Files[isfd]->curr.keyProg,
                                    isKeyDup(isfd,Files[isfd]->currIndex),
                                    ISTRUE);
               if (found != 0) {
                  lockData(isfd, mode, found->numRec);
                  readData(isfd,(unsigned char *) record,flagcan);
                  checkBadFile(flagcan);
                  copyStruct(Files[isfd]->curr,*found);
               } else {
                  pIserrno = EENDFILE;
                  Files[isfd]->next.numRec = MAXRECNUM;
                  RETURN;
               }
            }
            pIsrecnum = Files[isfd]->curr.numRec;
            Return = 0;
            if (Files[isfd]->curr.numRec == Files[isfd]->next.numRec) {
               found = _pI__next(isfd, Files[isfd]->currIndex,
                                       Files[isfd]->curr.keyVal,
                                       Files[isfd]->curr.nodeAddr,
                                       Files[isfd]->curr.keyProg,
                                       isKeyDup(isfd,Files[isfd]->currIndex),
                                       ISFALSE);
               if (found != 0) {
                  copyStruct(Files[isfd]->next,*found);
               } else
                  Files[isfd]->next.numRec = MAXRECNUM;
            }
         }
         break;
      case ISNEXT:
         if (Files[isfd]->curr.numRec > Files[isfd]->dictInfo.di_nrecords){
               pIserrno = EENDFILE;
               RETURN
            }
         if (Files[isfd]->next.numRec == 0) {
            pIsstart (isfd, Files[isfd]->keyDesc[Files[isfd]->currIndex], 0,
                        record, ISFIRST);
            if (pIserrno == 0) {
               Return = _pI__read (isfd, record, mode);
               if (pIserrno != 0)
                  Files[isfd]->next.numRec = 0;
            } else if (pIserrno == ENOREC) {
               pIserrno = EENDFILE;
            }
         } else {
            if (Files[isfd]->next.numRec > Files[isfd]->dictInfo.di_nrecords ||
                Files[isfd]->next.numRec == 0) {
               pIserrno = EENDFILE;
               RETURN
            }
            if ((Files[isfd]->next.numRec = _pI__verifyCurr(isfd,
                                      Files[isfd]->currIndex,
                                      Files[isfd]->next.keyVal,
                                      Files[isfd]->next.nodeAddr,
                                      Files[isfd]->next.keyProg,
                                      isKeyDup(isfd,Files[isfd]->currIndex)))) {
               lockData(isfd, mode, Files[isfd]->next.numRec);
               readData(isfd,(unsigned char *) record,flagcan);
               checkBadFile(flagcan);
            } else {
               found = _pI__findKey (Files[isfd]->next.keyVal,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_rootnode,
                       Files[isfd]->currIndex,
                       isfd,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex], 
                       ISGTEQ,
                       isKeyDup(isfd,Files[isfd]->currIndex));
               if (found != 0)
                  found = _pI__next(isfd,
                                    Files[isfd]->currIndex,
                                    Files[isfd]->next.keyVal,
                                    found->nodeAddr,
                                    Files[isfd]->next.keyProg,
                                    isKeyDup(isfd,Files[isfd]->currIndex),
                                    ISTRUE);
               if (found != 0) {
                  lockData(isfd, mode, found->numRec);
                  readData(isfd,(unsigned char *) record,flagcan);
                  checkBadFile(flagcan);
                  copyStruct(Files[isfd]->next,*found);
               } else {
                  pIserrno = EENDFILE;
                  Files[isfd]->next.numRec = MAXRECNUM;
                  RETURN;
               }
            }
            pIsrecnum = Files[isfd]->next.numRec;
            copyStruct(Files[isfd]->curr,Files[isfd]->next);
            Return = 0;

            found = _pI__next(isfd, Files[isfd]->currIndex,
                                    Files[isfd]->next.keyVal,
                                    Files[isfd]->next.nodeAddr,
                                    Files[isfd]->next.keyProg,
                                    isKeyDup(isfd,Files[isfd]->currIndex),
                                    ISFALSE);
            if (found != 0) {
               copyStruct(Files[isfd]->next,*found);
            } else
               Files[isfd]->next.numRec = MAXRECNUM;
         }
         break;
      case ISPREV:
         if (Files[isfd]->curr.numRec > Files[isfd]->dictInfo.di_nrecords) {
            copyStruct(Files[isfd]->curr,Files[isfd]->next);

            Files[isfd]->next.numRec = MAXRECNUM;
            if ((Files[isfd]->curr.numRec = _pI__verifyCurr(isfd,
                                      Files[isfd]->currIndex,
                                      Files[isfd]->curr.keyVal,
                                      Files[isfd]->curr.nodeAddr,
                                      Files[isfd]->curr.keyProg,
                                      isKeyDup(isfd,Files[isfd]->currIndex)))) {
               ;
            } else {
               found = _pI__findKey (Files[isfd]->curr.keyVal,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_rootnode,
                       Files[isfd]->currIndex,
                       isfd,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex], 
                       ISLTEQ,
                       isKeyDup(isfd,Files[isfd]->currIndex));
               if (found != 0)
                  found = _pI__prev(isfd,
                                    Files[isfd]->currIndex,
                                    Files[isfd]->curr.keyVal,
                                    found->nodeAddr,
                                    Files[isfd]->curr.keyProg,
                                    isKeyDup(isfd,Files[isfd]->currIndex),
                                    ISTRUE);
               if (found != 0) {
                  copyStruct(Files[isfd]->curr,*found);
               } else {
                  pIserrno = EENDFILE;
                  RETURN;
               }
            }
         } else {
            if (Files[isfd]->curr.numRec != 0)
               copyStruct(Files[isfd]->next,Files[isfd]->curr);
            if ((Files[isfd]->next.numRec = _pI__verifyCurr(isfd,
                                      Files[isfd]->currIndex,
                                      Files[isfd]->next.keyVal,
                                      Files[isfd]->next.nodeAddr,
                                      Files[isfd]->next.keyProg,
                                      isKeyDup(isfd,Files[isfd]->currIndex))))
               found = &Files[isfd]->next;
            else
               found = _pI__findKey (Files[isfd]->next.keyVal,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_rootnode,
                       Files[isfd]->currIndex,
                       isfd,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex], 
                       ISLTEQ,
                       isKeyDup(isfd,Files[isfd]->currIndex));
            if (found == 0) {
               pIserrno = EENDFILE;
               RETURN
            }
            found = _pI__prev(isfd, Files[isfd]->currIndex,
                                    Files[isfd]->next.keyVal,
                                    found->nodeAddr,
                                    Files[isfd]->next.keyProg,
                                    isKeyDup(isfd,Files[isfd]->currIndex),
                                    ISFALSE);
            if (found != 0) {
               copyStruct(Files[isfd]->curr,*found);
            } else {
               pIserrno = EENDFILE;
               RETURN
            }
         }
         if (Files[isfd]->curr.numRec > Files[isfd]->dictInfo.di_nrecords ||
            Files[isfd]->curr.numRec == 0) {
            pIserrno = EENDFILE;
            RETURN
         }
         lockData(isfd, mode, Files[isfd]->curr.numRec);
         readData(isfd,(unsigned char *) record,flagcan);
         checkBadFile(flagcan);
         pIsrecnum = Files[isfd]->curr.numRec;
         Return = 0;
         break;
      case ISFIRST:
         pIsstart (isfd, Files[isfd]->keyDesc[Files[isfd]->currIndex],
                        Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_len,
                        record, ISFIRST);
         if (pIserrno == 0)
            Return = _pI__read (isfd, record, ISNEXT|getLockMode(mode));
         break;
      case ISLAST:
         pIsstart (isfd, Files[isfd]->keyDesc[Files[isfd]->currIndex],
                        Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_len,
                        record, ISLAST);
         if (pIserrno == 0)
            Return = _pI__read (isfd, record, ISPREV|getLockMode(mode));
         break;
      case ISEQUAL:
         pIsstart (isfd, Files[isfd]->keyDesc[Files[isfd]->currIndex],
                        Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_len,
                        record, ISEQUAL);
         if (pIserrno == 0)
            Return = _pI__read (isfd, record, ISNEXT|getLockMode(mode));
         break;
      case ISGREAT:
         pIsstart (isfd, Files[isfd]->keyDesc[Files[isfd]->currIndex],
                        Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_len,
                        record, ISGREAT);
         if (pIserrno == 0)
            Return = _pI__read (isfd, record, ISNEXT|getLockMode(mode));
         break;
      case ISGTEQ:
         pIsstart (isfd, Files[isfd]->keyDesc[Files[isfd]->currIndex],
                        Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_len,
                        record, ISGTEQ);
         if (pIserrno == 0)
            Return = _pI__read (isfd, record, ISNEXT|getLockMode(mode));
         break;
      case ISLESS:
         pIsstart (isfd, Files[isfd]->keyDesc[Files[isfd]->currIndex],
                        Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_len,
                        record, ISLESS);
         if (pIserrno == 0)
            Return = _pI__read (isfd, record, ISPREV|getLockMode(mode));
         break;
      case ISLTEQ:
         pIsstart (isfd, Files[isfd]->keyDesc[Files[isfd]->currIndex],
                        Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_len,
                        record, ISLTEQ);
         if (pIserrno == 0)
            Return = _pI__read (isfd, record, ISPREV|getLockMode(mode));
         break;

      default:
         pIserrno = EBADARG;
         RETURN
      }
   }
   RETURN
}

int ISAM_API
pIsread (FILEDESC isfd, char * record, int mode )
{
   int Return = -1;

   pIserrno = 0;
   pIsrecnum = 0;

# ifdef ISAMDEBUG
   fprintf (stderr, "pIsread        file=%s, mode=%d\n",Files[isfd]->dataName,mode);
# endif

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISOUTPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   if (getWaitMode(mode) == ISWAIT) {
      int lastErr;
      RECNUM lockRec = 0;
      do {
         Return = _pI__read (isfd, record, mode);
         lastErr = pIserrno;
         if (lockRec != 0 && lockRec != pIsrecnum)
            _pI__recordUnlock (isfd, lockRec);
         if (lastErr == ELOCKED) {
            pIserrno = 0;
            _pI__recordLock (isfd, pIsrecnum,ISTRUE);
            lockRec = pIsrecnum;
         } 
      } while (lastErr == ELOCKED);
   } else
      Return = _pI__read (isfd, record, mode);
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsread        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   return Return;
}

int ISAM_API
pIsdelrec (FILEDESC isfd, RECNUM recnum)
{
   int Return = -1;
   unsigned char flagcan;
   register short i;
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsdelrec         file=%s\n",Files[isfd]->dataName);
# endif

   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
       RETURN
   if (recnum == 0 || recnum > Files[isfd]->dictInfo.di_nrecords) {
      pIserrno = EBADARG;
      RETURN
   }
   pIsrecnum = recnum;
   _pI__recordLock(isfd, pIsrecnum, ISFALSE);
   if (pIserrno != 0)
      RETURN;
   dataLseek(isfd,pIsrecnum);
   readData(isfd, Files[isfd]->record, flagcan);
   if (flagcan == 0) {
      pIserrno = ENOREC;
      _pI__recordUnlock(isfd, pIsrecnum);
      RETURN;
   }
   checkBadFile(flagcan);
   for (i = 0; pIserrno == 0 && i < Files[isfd]->dictInfo.di_nkeys; i++) {
      if (Files[isfd]->keyDesc[i]->k_nparts > 0) {
         _pI__buildKey (isfd, i, Files[isfd]->record,
                        Files[isfd]->keySup[i]->bufKey);
         _pI__deleteKey (Files[isfd]->keySup[i]->bufKey,
                         Files[isfd]->keyDesc[i]->k_rootnode, i, isfd,
                         Files[isfd]->keyDesc[i], isKeyDup(isfd,i), pIsrecnum);
      }
   }
   if (pIserrno == 0) {
      _pI__storeRecDel (isfd, pIsrecnum);
      _pI__writeHeader (isfd);
   }
   if (pIserrno == 0) {
      dataLseek(isfd,pIsrecnum);
      deleteData(isfd);
#ifdef TRANSACTION
      if (beginWork && isOpenTrans(Files[isfd]->openMode))
         Return = _pI__transaction (TNX_DELETE, isfd, pIsrecnum,
                      Files[isfd]->record, Files[isfd]->dictInfo.di_recsize,
                      0, 0);
      else
#endif
      Return = 0;
   }
#ifdef AUDIT_TRAIL
   auditTrail(isfd,'d',Files[isfd]->record);
#endif
   _pI__recordUnlock (isfd, pIsrecnum);
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsdelrec         Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

int ISAM_API
pIsdelcurr (FILEDESC isfd)
{
   int Return = -1;
   unsigned char flagcan;
   register short i;
   NodeItemDesc *found;
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsdelcurr        file=%s\n",Files[isfd]->dataName);
# endif

   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
       RETURN
   if (Files[isfd]->curr.numRec == 0 ||
          Files[isfd]->curr.numRec > Files[isfd]->dictInfo.di_nrecords) {
      pIserrno = ENOCURR;
      RETURN
   }
   pIsrecnum = Files[isfd]->curr.numRec;
   if (Files[isfd]->currIndex != -1 &&
          Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_nparts != 0) {
      if (pIsrecnum != _pI__verifyCurr(isfd,
                                  Files[isfd]->currIndex,
                                  Files[isfd]->curr.keyVal,
                                  Files[isfd]->curr.nodeAddr,
                                  Files[isfd]->curr.keyProg,
                                 isKeyDup(isfd,Files[isfd]->currIndex))) {
         found = _pI__findKey (Files[isfd]->curr.keyVal,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex]->k_rootnode,
                       Files[isfd]->currIndex,
                       isfd,
                       Files[isfd]->keyDesc[Files[isfd]->currIndex], 
                       ISGTEQ,
                       isKeyDup(isfd,Files[isfd]->currIndex));
         if (found != 0)
            found = _pI__next(isfd,
                              Files[isfd]->currIndex,
                              Files[isfd]->curr.keyVal,
                              found->nodeAddr,
                              Files[isfd]->curr.keyProg,
                              isKeyDup(isfd,Files[isfd]->currIndex),
                              ISTRUE);
         if (found == 0 || found->numRec != pIsrecnum) {
            pIserrno = ENOREC;
            RETURN
         }
      }
   }
   _pI__recordLock(isfd, pIsrecnum, ISFALSE);
   if (pIserrno != 0)
      RETURN;
   dataLseek(isfd,pIsrecnum);
   readData(isfd,Files[isfd]->record,flagcan);
   if (flagcan == 0) {
      pIserrno = ENOREC;
      _pI__recordUnlock(isfd, pIsrecnum);
      RETURN;
   }
   for (i = 0; i < Files[isfd]->dictInfo.di_nkeys; i++) {
      if (Files[isfd]->keyDesc[i]->k_nparts > 0) {
         _pI__buildKey (isfd, i, Files[isfd]->record,
                        Files[isfd]->keySup[i]->bufKey);
         _pI__deleteKey (Files[isfd]->keySup[i]->bufKey,
                         Files[isfd]->keyDesc[i]->k_rootnode, i, isfd,
                         Files[isfd]->keyDesc[i], isKeyDup(isfd,i), pIsrecnum);
      }
   }
   if (pIserrno == 0) {
      _pI__storeRecDel (isfd, pIsrecnum);
      _pI__writeHeader(isfd);
   }
   if (pIserrno == 0) {
      Files[isfd]->curr.numRec = 0;
      dataLseek(isfd,pIsrecnum);
      deleteData(isfd);
#ifdef TRANSACTION
      if (beginWork && isOpenTrans(Files[isfd]->openMode))
         Return = _pI__transaction (TNX_DELETE, isfd, pIsrecnum,
                         Files[isfd]->record, Files[isfd]->dictInfo.di_recsize,
                         0, 0);
      else
#endif
      Return = 0;
   }
#ifdef AUDIT_TRAIL
   auditTrail(isfd,'d',Files[isfd]->record);
#endif
   _pI__recordUnlock (isfd, pIsrecnum);
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsdelcurr        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

int ISAM_API
pIsrewrite (FILEDESC isfd, char * record)
{
   int Return = -1;
   NodeItemDesc *found;
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsrewrite        file=%s\n",Files[isfd]->dataName);
# endif

   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
       RETURN

   _pI__buildKey (isfd, 0, (unsigned char *)record, Files[isfd]->keySup[0]->bufKey);

   found = _pI__findKey (Files[isfd]->keySup[0]->bufKey,
                 Files[isfd]->keyDesc[0]->k_rootnode, 0, isfd,
                 Files[isfd]->keyDesc[0], ISEQUAL, isKeyDup(isfd,0));
   if (found != 0)
      Return = pIsrewrec (isfd, found->numRec, record);
   else if (pIserrno == 0)
      pIserrno = ENOREC;

# ifdef ISAMDEBUG
   fprintf (stderr, "pIsrewrite        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

int ISAM_API
pIsrewcurr (FILEDESC isfd, char * record)
{
   int Return = -1;
   pIserrno = 0;

   checkIsOpen(isfd);

   if (Files[isfd]->curr.numRec == 0 ||
       Files[isfd]->curr.numRec > Files[isfd]->dictInfo.di_nrecords) {
      pIserrno = ENOCURR;
      RETURN
   }
   Return = pIsrewrec (isfd, Files[isfd]->curr.numRec, record);

   RETURN
}
 
int ISAM_API
pIsrewrec (FILEDESC isfd, RECNUM recnum, char * record)
{
   register short i;
   int Return = -1;
   char flagcan = 0;
   NodeItemDesc *found;
   NewNodes *kaa;
   ADDR newRoot;
   unsigned char keyBuf[MAXKEYSIZE + sizeof(RECNUM)];


   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   if (recnum == 0) {
      pIserrno = EENDFILE;
      RETURN
   } else if (recnum > Files[isfd]->dictInfo.di_nrecords) {
      pIserrno = EENDFILE;
      RETURN
   }

   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
      RETURN
   
   for (i = 0; i < Files[isfd]->dictInfo.di_nkeys; i++) {
      if (Files[isfd]->keyDesc[i]->k_nparts > 0) {
         _pI__buildKey (isfd, i, (unsigned char *)record, Files[isfd]->keySup[i]->bufKey);

         if (!isKeyDup(isfd,i)) {
            found = _pI__findKey (Files[isfd]->keySup[i]->bufKey,
                       Files[isfd]->keyDesc[i]->k_rootnode, i, isfd,
                       Files[isfd]->keyDesc[i], ISEQUAL, isKeyDup(isfd,i));
            if (found != 0 && found->numRec != recnum) {
               pIserrno = EDUPL;
           RETURN;
            }
         }
      }
   }
   pIsrecnum = recnum;
   _pI__recordLock(isfd, pIsrecnum, ISFALSE);
   if (pIserrno != 0)
      RETURN;
   dataLseek(isfd,pIsrecnum);
   readData(isfd, Files[isfd]->record, flagcan);
   if (flagcan == 0) {
      pIserrno = ENOREC;
      _pI__recordUnlock(isfd, pIsrecnum);
      RETURN;
   }
   checkBadFile(flagcan);

   for (i = 0; i < Files[isfd]->dictInfo.di_nkeys; i++) {
      _pI__buildKey (isfd, i, Files[isfd]->record,
                     Files[isfd]->keySup[i]->bufKey);
      _pI__buildKey (isfd, i, (unsigned char *) record, keyBuf);
      if (memcmp (Files[isfd]->keySup[i]->bufKey, keyBuf,
                  Files[isfd]->keyDesc[i]->k_len)) {
         _pI__deleteKey (Files[isfd]->keySup[i]->bufKey,
                         Files[isfd]->keyDesc[i]->k_rootnode, i, isfd,
                         Files[isfd]->keyDesc[i], isKeyDup(isfd,i), pIsrecnum);

         kaa = _pI__insertKey (keyBuf,Files[isfd]->keyDesc[i]->k_rootnode,
                               i, isfd, pIsrecnum);
         if (pIserrno != 0) {
#ifdef AUDIT_TRAIL
            auditTrail(isfd,'r',Files[isfd]->record);
            auditTrail(isfd,'w',record);
#endif
            _pI__recordUnlock (isfd, pIsrecnum);
            RETURN
         } else if (kaa != 0 ) {
            if ((newRoot = _pI__newRoot (kaa, isfd, i)) != 0)
               Files[isfd]->keyDesc[i]->k_rootnode = newRoot;
            else {
#ifdef AUDIT_TRAIL
               auditTrail(isfd,'r',Files[isfd]->record);
               auditTrail(isfd,'w',record);
#endif
               _pI__recordUnlock (isfd, pIsrecnum);
               RETURN
            }
         }
      } 
   }
   _pI__writeHeader (isfd);
   if (pIserrno == 0) {
      dataLseek(isfd, pIsrecnum);
      writeData (isfd, (unsigned char *) record);
      Return = 0;
#ifdef TRANSACTION
      if (beginWork && isOpenTrans(Files[isfd]->openMode))
         Return = _pI__transaction (TNX_UPDATE, isfd, pIsrecnum,
                         Files[isfd]->record, Files[isfd]->dictInfo.di_recsize,
                         record, Files[isfd]->dictInfo.di_recsize);
      else
#endif
      _pI__recordUnlock (isfd, pIsrecnum);
   } else
      _pI__recordUnlock (isfd, pIsrecnum);
#ifdef AUDIT_TRAIL
   auditTrail(isfd,'r',Files[isfd]->record);
   auditTrail(isfd,'w',record);
#endif

   RETURN
}

int ISAM_API
pIsdelete (FILEDESC isfd, char * record)
{
   register short i;
   int Return = -1;
   char flagcan = 0;
   NodeItemDesc *found;
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsdelete        file=%s\n",Files[isfd]->dataName);
# endif

   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
       RETURN

   _pI__buildKey (isfd, 0, (unsigned char *)record, Files[isfd]->keySup[0]->bufKey);

   found = _pI__findKey (Files[isfd]->keySup[0]->bufKey,
                 Files[isfd]->keyDesc[0]->k_rootnode, 0, isfd,
                 Files[isfd]->keyDesc[0], ISEQUAL, isKeyDup(isfd,0));
   if (found != 0) {
      pIsrecnum = found->numRec;
      _pI__recordLock(isfd, pIsrecnum, ISFALSE);
      if (pIserrno != 0)
         RETURN;
      dataLseek(isfd,pIsrecnum);
      readData(isfd, Files[isfd]->record, flagcan);
      checkBadFile(flagcan);
      _pI__deleteKey (Files[isfd]->keySup[0]->bufKey,
                      Files[isfd]->keyDesc[0]->k_rootnode, 0, isfd,
                      Files[isfd]->keyDesc[0], isKeyDup(isfd,0), pIsrecnum);
      for (i = 1; pIserrno == 0 && i < Files[isfd]->dictInfo.di_nkeys; i++) {
         _pI__buildKey (isfd, i, Files[isfd]->record,
                        Files[isfd]->keySup[i]->bufKey);
         _pI__deleteKey (Files[isfd]->keySup[i]->bufKey,
                         Files[isfd]->keyDesc[i]->k_rootnode, i, isfd,
                         Files[isfd]->keyDesc[i], isKeyDup(isfd,i), pIsrecnum);
      }
      if (pIserrno == 0) {
         _pI__storeRecDel (isfd, pIsrecnum);
         _pI__writeHeader (isfd);
      }
      if (pIserrno == 0) {
         dataLseek(isfd,pIsrecnum);
         deleteData(isfd);
#ifdef TRANSACTION
         if (beginWork && isOpenTrans(Files[isfd]->openMode))
            Return = _pI__transaction (TNX_DELETE, isfd, pIsrecnum,
                         Files[isfd]->record, Files[isfd]->dictInfo.di_recsize,
                         0, 0);
         else
#endif
         Return = 0;
      }
   } else if (pIserrno == 0)
      pIserrno = ENOREC;
#ifdef AUDIT_TRAIL
   auditTrail(isfd,'d',Files[isfd]->record);
#endif
   _pI__recordUnlock (isfd, pIsrecnum);
# ifdef ISAMDEBUG
   fprintf (stderr, "pIsdelete        Return=%d, pIserrno=%d\n", Return, pIserrno);
# endif
   RETURN
}

int ISAM_API
pIswrcurr (FILEDESC isfd, char * record)
{
   int Return = -1;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }

   Return = pIswrite (isfd, record);
   
   if (pIserrno == 0) {
      Files[isfd]->currIndex = -1;
      Files[isfd]->curr.numRec = pIsrecnum;
   }
   RETURN
}

#ifdef AUDIT_TRAIL
int ISAM_API
pIsaudit (FILEDESC isfd, char *fname, int mode)
{
   int Return = 0;
   pIserrno = 0;
   checkIsOpen(isfd);
   switch (mode) {
   case AUDSETNAME:
      if (Files[isfd]->auditName)
         free (Files[isfd]->auditName);
      Files[isfd]->auditName = 0;
      if (fname)
         Files[isfd]->auditName = strdup (fname);
      else {
         pIserrno = EBADARG;
         Return = FILEDESC_ERROR;
      }
      break;
   case AUDGETNAME:
      if (Files[isfd]->auditName && fname)
         strcpy (fname, Files[isfd]->auditName);
      else {
         pIserrno = EBADARG;
         Return = FILEDESC_ERROR;
      }
      break;
   case AUDSTART:
      if (Files[isfd]->auditFd < 0) {
         if (Files[isfd]->auditName) {
            if ((Files[isfd]->auditFd = open (Files[isfd]->auditName,
# if defined(MSDOS) || defined(WIN32)
                                              O_WRONLY|O_CREAT|O_APPEND|O_BINARY,
# elif !defined(HAS_FSYNC) && !defined(HAS_FDATASYNC)
                                              O_WRONLY|O_CREAT|O_APPEND|O_SYNC,
# else
                                              O_WRONLY|O_CREAT|O_APPEND,
# endif
                                              0666)) < 0) {
               pIserrno = pIserrio = errno;
               Return = FILEDESC_ERROR;
            }
         } else {
            pIserrno = EBADARG;
            Return = FILEDESC_ERROR;
         }
      }
      break;
   case AUDSTOP:
      if (Files[isfd]->auditFd >= 0) {
         close (Files[isfd]->auditFd);
         Files[isfd]->auditFd = -1;
      }
      break;
   case AUDINFO:
      if (fname)
         fname[0] = (Files[isfd]->auditFd >= 0) ? 1 : 0;
      else {
         pIserrno = EBADARG;
         Return = FILEDESC_ERROR;
      }
      break;
   }
   RETURN
}
#endif

UINT4  ISAM_API
pIsGetRecnum(void)
{
   return pIsrecnum;
}

void ISAM_API
pIsSetRecnum(UINT4 r)
{
   pIsrecnum = r;
}

int  ISAM_API
pIsGetErrno(void)
{
   return pIserrno;
}

int  ISAM_API
pIsGetVersion(FILEDESC isfd)
{
   int Return = -1;
   checkIsOpen(isfd);
   Return = Files[isfd]->releaseLevel;
   return Return;
}

int ISAM_API
pIsrebuild (FILEDESC isfd)
{
   int Return = -1;
   register short i;
   unsigned char * pnt = headerArea;
   int newIdxFd;
   char *newName;
   int nameLen;
   struct keydesc **tmpDesc;
   struct keysup **tmpSup;
   struct stat file;
   int keyvecsize;
   int nkeys;
   int recsize;
   unsigned char *record;

   pIserrno = 0;

   checkIsOpen(isfd);
   if (getOpenMode(Files[isfd]->openMode) == ISINPUT) {
      pIserrno = EBADOPENMODE;
      RETURN
   }
   _pI__readHeader (isfd, ISTRUE);
   if (pIserrno != 0)
       RETURN

   if (getLockMode(Files[isfd]->openMode) != ISEXCLLOCK) {
      pIserrno = ENOTEXCL;
      RETURN
   }
   if (fstat(Files[isfd]->fdIndex, &file) == -1) {
      pIserrno = pIserrio = errno;
      RETURN;
   }
   nameLen = strlen (Files[isfd]->indexName);
   newName = malloc (nameLen + 1);
   strcpy (newName, Files[isfd]->indexName);
   newName[nameLen - 3] = 't';
   newName[nameLen - 2] = 'm';
   newName[nameLen - 1] = 'p';
# if defined(MSDOS) || defined(WIN32)
   if ((newIdxFd = open (newName, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666)) < 0) {
# else
   if ((newIdxFd = open (newName, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) {
# endif
      pIserrno = errno;
      RETURN
   }
# if !defined (MSDOS) && !defined(WIN32)
   fchmod (newIdxFd, file.st_mode);
   fchown (newIdxFd, file.st_uid, file.st_gid);
# endif
   close (Files[isfd]->fdIndex);
   Files[isfd]->fdIndex = newIdxFd;
   Files[isfd]->firstFreeNode = Files[isfd]->headerSize;
   Files[isfd]->firstAddKeyNode = 0L;
   Files[isfd]->firstDeletedNode = 0L;
   Files[isfd]->firstDelRecNode = 0L;
   nkeys = Files[isfd]->dictInfo.di_nkeys;
   Files[isfd]->dictInfo.di_nkeys = 0;

   memset(headerArea, 0, Files[isfd]->headerSize);
   pnt = headerArea;
   indexLseek (isfd, 0L);
/* 0-5 Signature */
   memcpy (pnt, SIGN, 6);
   pnt+=6;
/* 6-7 Release */
   putShortInBuffer(pnt,Files[isfd]->releaseLevel);

/* 8-11 first free node */
   putLongInBuffer(pnt, Files[isfd]->firstFreeNode);

/* 12-13 number of keys */
   putShortInBuffer(pnt,Files[isfd]->dictInfo.di_nkeys);
/* 14-15 recsize  */
   putShortInBuffer(pnt,Files[isfd]->dictInfo.di_recsize);
/* 16-17 index record size  */
   putShortInBuffer(pnt,Files[isfd]->dictInfo.di_idxsize);
/* 18-21 number of record */
   putLongInBuffer(pnt,Files[isfd]->dictInfo.di_nrecords);
/* 22-23 header dimension */
   putShortInBuffer(pnt, Files[isfd]->headerSize);
/* 24-27 first deleted node */
   putLongInBuffer(pnt, Files[isfd]->firstDeletedNode);
/* 28-31 first deleted record node */
   putLongInBuffer(pnt, Files[isfd]->firstDelRecNode);
/* <last four bytes> first additional key node */
   pnt = headerArea + Files[isfd]->headerSize - sizeof(ADDR);
   putLongInBuffer(pnt, Files[isfd]->firstAddKeyNode);

   if (write (Files[isfd]->fdIndex, headerArea, Files[isfd]->headerSize) !=
                                                Files[isfd]->headerSize) {
      pIserrno = pIserrio = errno;
      RETURN
   }
   tmpDesc = Files[isfd]->keyDesc;
   tmpSup = Files[isfd]->keySup;
   keyvecsize = Files[isfd]->keyVecSize;
   Files[isfd]->keyDesc = 0;
   Files[isfd]->keySup = 0;
   Files[isfd]->keyVecSize = 0;
   for (i = 0, Return = 0; i < nkeys && Return == 0; i++) {
      Return = pIsaddindex (isfd, tmpDesc[i]);
      free (tmpDesc[i]);
      free (tmpSup[i]);
   }
   free (tmpDesc);
   free (tmpSup);

   if (Return == 0) {
      dataLseek(isfd,1);
      recsize = Files[isfd]->dictInfo.di_recsize + 1;
      record = Files[isfd]->record;
      for (pIsrecnum = 1, Files[isfd]->dictInfo.di_nrecords = 0;
           read(Files[isfd]->fdData,Files[isfd]->record,recsize) == recsize;
           pIsrecnum++, Files[isfd]->dictInfo.di_nrecords++)
         if (record[Files[isfd]->dictInfo.di_recsize] != '\n')
            _pI__storeRecDel (isfd, pIsrecnum);
      _pI__writeHeader(isfd);
   
      unlink (Files[isfd]->indexName);
      rename (newName, Files[isfd]->indexName);
   } else 
      unlink (newName);
   free (newName);

   return Return;
}
# if defined (WIN32) || defined (MSDOS)

int ISAM_API
pIslockWait (FILEDESC isfd)
{
   int Return = -1;
   pIserrno = 0;

   checkIsOpen(isfd);
   if (getLockMode(Files[isfd]->openMode) == ISMANULOCK) {
      if (Files[isfd]->fileLock == 0) {
         lseek (Files[isfd]->fdData, 0L, 0);
         errno = 0;
         while (_locking(Files[isfd]->fdData, _LK_LOCK , 0x7FFFFFFFL) &&
                errno == EDEADLOCK)
            errno = 0;
         if (errno) {
            pIserrio = errno;
            pIserrno = errno;
         } else
            Files[isfd]->fileLock = 1;
      }
   } else
      pIserrno = EBADOPENMODE;

   if (pIserrno == 0)
      Return = 0;
   RETURN
}

# else
int ISAM_API
pIslockWait (FILEDESC isfd)
{
   int Return = -1;
   pIserrno = 0;

   checkIsOpen(isfd);
   if (getLockMode(Files[isfd]->openMode) == ISMANULOCK) {
      if (Files[isfd]->fileLock == 0) {
         struct flock lck;
         lck.l_whence = 0;
         lck.l_start = 0;
         lck.l_len = 0;
         lck.l_type = F_WRLCK;
         if (fcntl(Files[isfd]->fdData, F_SETLKW, &lck) == -1) {
            pIserrio = errno;
            pIserrno = errno;
         } else
            Files[isfd]->fileLock = 1;
      }
   } else
      pIserrno = EBADOPENMODE;

   if (pIserrno == 0)
      Return = 0;
   RETURN
}
# endif

int ISAM_API
pIswriteLock (FILEDESC isfd, char * record)
{
   int Return = -1;

# ifdef ISAMDEBUG
   fprintf (stderr, "pIswriteLock    file=%s\n",Files[isfd]->dataName);
# endif
   pIserrno = 0;
   if ((Return = pIswrite (isfd, record)) == 0) {
      lockData(isfd, ISLOCK, pIsrecnum);
   }
   RETURN
}

# ifdef TRANSACTION

static int
rollback (unsigned short tnxType, short isfd, unsigned long recNum,
          char *beforeImage, unsigned short biLen,
          char *afterImage, unsigned short aiLen)
{
   int Return = 0;

   switch (tnxType) {
   case TNX_BEGIN_WORK:
   case TNX_COMMIT_WORK:
   case TNX_ROLLBACK_WORK:
   case TNX_FILE_OPEN:
   case TNX_FILE_CLOSE:
      break;
   case TNX_INSERT:
      Return = pIsdelrec (isfd, recNum);
      break;
   case TNX_UPDATE:
      Return = pIsrewrec (isfd, recNum, beforeImage);
      break;
   case TNX_DELETE:
      Return = pIswrite (isfd, beforeImage);
      break;
   }

   return Return;
}

static int
commit (unsigned short tnxType, short isfd, unsigned long recNum,
        char *beforeImage, unsigned short biLen,
        char *afterImage, unsigned short aiLen)
{
   int Return = 0;

   return Return;
}

static void
initTrans()
{
   static ISBOOL initTransFlag = ISFALSE;

   if (initTransFlag == ISFALSE) {
      int i;
      for (i = 0; i < MAXOPENFILE; i++)
         fileToClose[i] = FILEDESC_ERROR;
      nFileToClose = 0;
      _pI__logOpen (0, commit, rollback);
      initTransFlag = ISTRUE;
   }
}

int ISAM_API
pIslogopen (char * fileName)
{
   int Return;
   initTrans();
   Return = _pI__logOpen (fileName, commit, rollback);
   return Return;
}

int ISAM_API
pIslogclose ()
{
   int Return;
   if (beginWork == ISFALSE) {
      Return = _pI__logClose ();
   } else {
      pIserrno = EBADARG; /* ? Cannot close log in transaction */
      Return = -1;
   }
   return Return;
}

int ISAM_API
pIsbegin ()
{
   int Return = -1;

   pIserrno = 0;
   initTrans();
   if (beginWork == ISFALSE) {
      Return = _pI__transaction (TNX_BEGIN_WORK, 0, 0, 0, 0, 0, 0);
      beginWork = ISTRUE;
   } else {
      Return = -1;
      pIserrno = EBADARG;
   }
   return Return;
}

int ISAM_API
pIscommit ()
{
   int i;
   int Return = -1;

   if (beginWork) {
      beginWork = ISFALSE;
      Return = _pI__transaction (TNX_COMMIT_WORK, 0, 0, 0, 0, 0, 0);
      for (i = 0; i < nFileToClose; i++) {
         if (fileToClose[i] != FILEDESC_ERROR) {
            pIsclose (fileToClose[i]);
            fileToClose[i] = FILEDESC_ERROR;
         }
      }
      nFileToClose = 0;
      for (i = 0; i < MAXOPENFILE; i++)
         if (Files[i] != 0)
            pIsrelease(i);
   } else {
      Return = -1;
      pIserrno = ENOTRANS;
   }
   return Return;
}

int ISAM_API
pIsrollback ()
{
   int i;
   int Return = -1;

   if (beginWork) {
      int errnoBkp;

      beginWork = ISFALSE;
      Return = _pI__transaction (TNX_ROLLBACK_WORK, 0, 0, 0, 0, 0, 0);
      errnoBkp = pIserrno;
      for (i = 0; i < nFileToClose; i++) {
         if (fileToClose[i] != FILEDESC_ERROR) {
            pIsclose (fileToClose[i]);
            fileToClose[i] = FILEDESC_ERROR;
         }
      }
      nFileToClose = 0;
      for (i = 0; i < MAXOPENFILE; i++)
         if (Files[i] != 0)
            pIsrelease(i);
      pIserrno = errnoBkp;
   } else {
      Return = -1;
      pIserrno = ENOTRANS;
   }
   return Return;
}

static int
recover (unsigned short tnxType, char *name, unsigned long recNum,
         char *beforeImage, unsigned short biLen,
         char *afterImage, unsigned short aiLen)
{
   int Return = -1;
   short isfd = pIsopen (name, ISINOUT|ISEXCLLOCK);
   if (isfd >= 0) {
      switch (tnxType) {
      case TNX_INSERT:
         Return = pIswrite (isfd, afterImage);
         break;
      case TNX_UPDATE:
         Return = pIsrewrec (isfd, recNum, afterImage);
         break;
      case TNX_DELETE:
         Return = pIsdelrec (isfd, recNum);
         break;
      }
      pIsclose (isfd);
   }
   return Return;
}

int ISAM_API
pIsrecover ()
{
   return _pI__recover (recover);
}

# endif
