/*
----------------------------------------------------------------------
isam base library header file
----------------------------------------------------------------------

         +----------------------------------------------------+
         |  Worldwide Copyright (c) Byte Designs Ltd (2001)   |    
         |                                                    |
         |               20568 - 32 Avenue                    |
         |               LANGLEY, BC                          |
         |               V3A 4P5 CANADA                       |
         |                                                    |
         |            Sales: sales@bytedesigns.com            |
         |          Support: support@bytedesigns.com          |
         | Phone: (604) 534 0722      Fax: (604) 534 2601     |
         +----------------------------------------------------+
                            Version 6.12
 
----------------------------------------------------------------------
*/

#include <isconfig.h>                   /* library configuration */
#include <setjmp.h>                     /* error handling */
#include <sys/types.h>

#ifndef ISINPUT

/* structures ----------------------------------------------------- */

struct keypart                          /* key component description */
  {
  short kp_start;                       /* offset within data record */
  short kp_leng;                        /* physical length */
  short kp_type;                        /* isam key type */
  };

struct keydesc                          /* full key description */
  {
  short k_flags;                        /* key characteristics */
  short k_nparts;                       /* number of parts in key */
  struct keypart k_part[ISMAXPARTS];    /* description of each part */
  short k_len;                          /* complete key length */
  long  k_rootnode;                     /* root node record number */
  };
  
struct dictinfo                         /* information about file */
  {
  short di_nkeys;                       /* number of indexes */
  short di_recsize;                     /* data record length */
  short di_idxsize;                     /* index record block size */
  long  di_nrecords;                    /* current record count */
  };

struct audhead                          /* audit record header format */
  {
  char au_type[2];                      /* record type (aa/dd/rr/ww) */
  char au_time[4];                      /* date and time */
#if( ISLONGID == 1 )
  char au_procid[4];                    /* process id */
  char au_userid[4];                    /* user id */
#else
  char au_procid[2];                    /* process id */
  char au_userid[2];                    /* user id */
#endif
  char au_recnum[4];                    /* record number */
  char au_reclen[2];                    /* record length if variable */
  };


/* defines ------------------------------------------------------- */
  
/* file handling modes */

#define ISINPUT         0x00            /* input only */
#define ISOUTPUT        0x01            /* output only */
#define ISINOUT         0x02            /* input and output */
#define ISTRANS         0x04            /* transaction processing */
#define ISNOLOG         0x08            /* turn off logging */
#define ISFIXLEN        0x00            /* dummy */
#define ISVARLEN        0x10            /* variable length data */
#define ISVARCMP        0x30            /* compressed varlen */
#define ISSYNCWR        0x40            /* synchronous writes */
#define ISMASKED        0x80            /* masking active */
#define ISNOCARE        0x8000          /* set mode to match file */

/* locking methods */

#define ISRDONLY        0x100           /* read only - no locking */
#define ISAUTOLOCK      0x200           /* automatic lock on read */
#define ISMANULOCK      0x400           /* manual locking */
#define ISEXCLLOCK      0x800           /* exclusive access to file */
#if( SEMILOCK == 1 )
#define ISSEMILOCK 	0x1000		/* c-isam compatible semi-lock */
#endif

/* key types */
 
#define CHARTYPE        0               /* array of bytes/characters */
#define DECIMALTYPE     0               /* handled as per char type */
#define INTTYPE         1               /* two byte (short) integer */
#define LONGTYPE        2               /* four byte (long) integer */
#define DOUBLETYPE      3               /* ieee double floating point */
#define FLOATTYPE       4               /* ieee single floating point */
#define MINTTYPE        5               /* machine (native) short */
#define MLONGTYPE       6               /* machine (native) long */
#define STRINGTYPE      7               /* null terminated byte string */

#define ISDESC          0x80            /* add for descending order */

/* key atomic sizes */

#define CHARSIZE        1
#define INTSIZE         2
#define LONGSIZE        4
#define DOUBLESIZE      8
#define FLOATSIZE       4
#define MINTSIZE        2
#define MLONGSIZE       4
#define STRINGSIZE      1

/* shortcuts for single part keys */

#define k_start   k_part[0].kp_start
#define k_leng    k_part[0].kp_leng
#define k_type    k_part[0].kp_type

#define NPARTS    ISMAXPARTS

/* index management flags */

#define ISNODUPS  0x00                  /* no duplicates permitted */
#define ISDUPS    0x01                  /* duplicates permitted */
#define DCOMPRESS 0x02                  /* compress duplicates */
#define LCOMPRESS 0x04                  /* leading compression */
#define TCOMPRESS 0x08                  /* trailing compression */
#define COMPRESS  0x0E                  /* full compression */
#define TNULL     0x10			/* compress trailing nulls */
#define NULLKEY   0x20                  /* null key masking */

#define ISMASK(I) ( 1L << ((I)-1) )     /* index masking bit flags */

/* access control */

#define ISFIRST         0               /* first record */
#define ISLAST          1               /* last record */
#define ISNEXT          2               /* next record */
#define ISPREV          3               /* previous record */
#define ISCURR          4               /* current record */
#define ISEQUAL         5               /* find match */
#define ISGREAT         6               /* greater than current */
#define ISGTEQ          7               /* greater than or equal */

/* record locking */

#define ISLOCK          0x100           /* lock record or fail */
#if( ISCISAM != 0 )
# define ISSKIPLOCK     0x200           /* skip record if locked */
#endif
#define ISWAIT          0x400           /* wait until free */
#define ISLCKW          0x500           /* wait and lock */

/* audit trace control */

#define AUDSETNAME      0               /* set audit file name */
#define AUDGETNAME      1               /* get audit file name */
#define AUDSTART        2               /* begin audit logging */
#define AUDSTOP         3               /* stop audit logging */
#define AUDINFO         4               /* logging status */

#define AUDHEADSIZE     14              /* audit header length */
#define VAUDHEADSIZE    16              /* if variable length */

#define USERINFOSIZE	10		/* userinfo pad size */

/* isam specific error codes (iserrno) */

#define EDUPL     ( ISERRBASE +  0 )    /* illegal duplicate */
#define ENOTOPEN  ( ISERRBASE +  1 )    /* file not open */
#define EBADARG   ( ISERRBASE +  2 )    /* illegal argument */
#define EBADKEY   ( ISERRBASE +  3 )    /* illegal key description */
#define ETOOMANY  ( ISERRBASE +  4 )    /* out of isam file handles */
#define EBADFILE  ( ISERRBASE +  5 )    /* isam file is corrupt */
#define ENOTEXCL  ( ISERRBASE +  6 )    /* can't get exclusive access */
#define ELOCKED   ( ISERRBASE +  7 )    /* record is locked */
#define EKEXISTS  ( ISERRBASE +  8 )    /* index already defined */
#define EPRIMKEY  ( ISERRBASE +  9 )    /* illegal primary key operation */
#define EENDFILE  ( ISERRBASE + 10 )    /* start or end file reached */
#define ENOREC    ( ISERRBASE + 11 )    /* record not found */
#define ENOCURR   ( ISERRBASE + 12 )    /* no current record */
#define EFLOCKED  ( ISERRBASE + 13 )    /* file is locked */
#define EFNAME    ( ISERRBASE + 14 )    /* file name is too long */
#define ENOLOK    ( ISERRBASE + 15 )    /* not used */
#define EBADMEM   ( ISERRBASE + 16 )    /* can't allocate memory */
#define EBADCOLL  ( ISERRBASE + 17 )    /* not used */
#define ELOGREAD  ( ISERRBASE + 18 )    /* error reading log file */
#define EBADLOG   ( ISERRBASE + 19 )    /* log file is corrupt */
#define ELOGOPEN  ( ISERRBASE + 20 )    /* unable to open log */
#define ELOGWRIT  ( ISERRBASE + 21 )    /* unable to write log */
#define ENOTRANS  ( ISERRBASE + 22 )    /* transaction not found */
#define ENOSHMEM  ( ISERRBASE + 23 )    /* out of shared memory */
#define ENOBEGIN  ( ISERRBASE + 24 )    /* no current transaction */
#define ENONFS    ( ISERRBASE + 25 )    /* not used */
#define EBADROWID ( ISERRBASE + 26 )    /* not used */
#define ENOPRIM   ( ISERRBASE + 27 )    /* no primary key */
#define ENOLOG    ( ISERRBASE + 28 )    /* logging not allowed */
#define EUSER     ( ISERRBASE + 29 )    /* too many users */
#define ENODBS    ( ISERRBASE + 30 )    /* not used */
#define ENOFREE   ( ISERRBASE + 31 )    /* not used */
#define EROWSIZE  ( ISERRBASE + 32 )    /* varlen record too big */
#define EAUDIT    ( ISERRBASE + 33 )    /* existing audit trail */
#define ENOLOCKS  ( ISERRBASE + 34 )    /* out of room in lock table */
#define EEXPIRED  ( ISERRBASE + 35 )    /* evaluation library has expired */
#define ENOCONNECT ( ISERRBASE + 36 )   /* no connect with remote server */
#define EREPAIR   ( ISERRBASE + 37 )    /* auto repair in progress */

/* on system error - iserrio = IO_call + IO_file */

#define IO_OPEN   0x10                  /* open */
#define IO_CREA   0x20                  /* create */
#define IO_SEEK   0x30                  /* seek */
#define IO_READ   0x40                  /* read */
#define IO_WRIT   0x50                  /* write */
#define IO_LOCK   0x60                  /* lock */
#define IO_IOCTL  0x70                  /* I/O control */

#define IO_IDX    0x01                  /* index file */
#define IO_DAT    0x02                  /* data file */
#define IO_AUD    0x03                  /* audit trace */
#define IO_LOK    0x04                  /* */
#define IO_SEM    0x05                  /* */
#define IO_LOG    0x06                  /* transaction log */
#define IO_LCK    0x07                  /* offline lock file */
#if( ISREPAIR == 1 )
#define IO_REP    0x08                  /* auto repair file  */
#endif

/* cobol isstat4 values --------------------------------------------*/

#define STATNULL       ' '              /* empty isstat4 value     */
#define STAT1          '1'
#define STAT2          '2'
#define STAT3          '3'
#define STAT4          '4'
#define STAT5          '5'
#define STAT6          '6'
#define STAT7          '7'
#define STAT8          '8'
#define STAT9          '9'
#define STAT0          '0'

/* self check facility ------------------------------------------- */

#define IC_DATREAD      0               /* data file read error */
#define IC_BADDATA      1               /* data record corrupt */
#define IC_DATFREE      2               /* data free list is corrupt */

#define IC_IDXREAD      3               /* index file read error */
#define IC_ORDER        4               /* key out of order */
#define IC_COUNT        5               /* index count mismatch */
#define IC_BADMAGIC     6               /* bad index node magic number */
#define IC_MATCH        7               /* index/data mismatch */

#if( ISVARIABLE )

#define IC_VLHASHZERO   11              /* hash table zero loaded */
#define IC_VLMISFILE    12              /* node misfiled in hash table */
#define IC_VLHASHLINK   13              /* mangled link in hash list */
#define IC_VLMISSING    14              /* nodes missing or unaccounted */
#define IC_VLBADDATA    15              /* data length mismatch */
  
struct isVarStat                        /* variable length statistics */
  {
  long hashcount;
  long hashspace;
  long fullcount;
  long fullspace;
  long filecount;
  long filespace;
  };
  
#endif 

#endif /*ISINPUT*/

/* useful defines ----------------------------------------------- */

#define ISTRUE  1
#define ISFALSE 0

/* convenient shortcuts ----------------------------------------- */

typedef struct IsamFile IsFile;
typedef struct keydesc  IsKdsc;

/* index file records -------------------------------------------- */

struct IsamNode                         /* index file record */
  {
  struct IsamNode *prev;                /* parent node */
  struct IsamNode *split;               /* sibling */

  long  idxrec;                         /* idx file record number */
  char  *image;                         /* disk image */
  char  state;                          /* current status */
  int   used;                           /* number of bytes used */
  int   level;                          /* zero is leaf node */
  
  int   keyoff;                         /* current key offset */
  int   keyend;                         /* end of compressed key */
  long  recnum;                         /* current record number */
  long  dupnum;                         /* current duplicate number */
  char  *keyval;                        /* key contents */
  };


/* index handling ------------------------------------------------ */

struct IsamPath                         /* index details */
  {
  struct keydesc *kdsc;                 /* key description */

  struct IsamNode *tail;                /* current path tail */

  struct IsamNode *buf[ISMAXBUF];       /* buffering system */
  
  int    slotlen;                       /* key slot length */
  int    duplen;                        /* valid if dups */
  
  int    partial;                       /* active partial length */
 
  char   current[ISMAXKEY];             /* current key value */
  long   recnum;                        /* current record number */
  long   dupnum;                        /* current dupnum i/a */
  int    cmplen;                        /* current compare */
  char   flags;                         /* bit flags */
  };


/* free list control structure ----------------------------------- */

struct IsamFree
  {
  char *image;                          /* index node image */
  char *split;                          /* hold for update */
  char state;                           /* update status */
  long root;                            /* list root record */
  long last;                            /* last used recnum */
  int used;                             /* bytes used in node */
  };
  
  
/* isam file descriptor ------------------------------------------ */

struct IsamFile                         /* isam file description */
  {
  char  *name;                          /* file pair path and name */
  int   openmode;                       /* open mode bit flags */
  short flags;                          /* bit flags */
  
  int   datfd;                          /* data file handle */
  int   datlen;                         /* data record length */
  int   datblk;                         /* data file record block */
  int   maxlen;                         /* variable length max */
  
  int   idxfd;                          /* index file handle */
  int   idxlen;                         /* index node size */
  int   duplen;                         /* duplicate sequence width */
  int   maxidx;                         /* number of indexes */
  int   curidx;                         /* current index number */

#if( ISLOCKING == 3 )
  int   lokfd;				/* lock file handle */
  long  lokid;				/* unique locking id */
#endif
  
  long  kdsc;                           /* key desc list root node */
  long  delta;                          /* concurrency control */
  long  unique;                         /* unique id value */

  struct IsamPath *path[ISMAXIDX];      /* active path array */

  struct IsamFree idxfree;              /* index free list */
  struct IsamFree datfree;              /* data free list */
  
  long *lklist;                         /* list of record locks */
  long lkllen;                          /* current list length */
  char lkstate;                         /* locking state flags */
  
#if( ISADMIN )
  int admid;                            /* admin table offset */
#endif
  
#if( ISAUDIT )
  long audit;                           /* audit control node */
  char audinfo[69];                     /* allocated info block */
  int  audfd;                           /* trace file handle */
#endif
  
#if( ISLOGGING )
  int txnpid;                           /* transaction process id */
  int txnfile;                          /* transaction file id */
#endif  
  
#if( ISVARIABLE )  
  long *hashtab;                        /* hash table array */
  char *varnode;                        /* varlen node image */
  char hashload;                        /* refresh flag */
#endif  

#if( ISVARIABLE > 1 )  
  long hashrecd;                        /* hash table record */
  char *hashnode;                       /* hash table image */
#endif  

#if( ISLKINFO == 1 )
  int ( *lkfilter )();                  /* lock filtering callback */
  char *lockinfo;                       /* lock information block */
#endif
  
  int ( *rdfilter )( int, char *, int );/* read filtering callback */

  long mask;                            /* index masking bit array */
  
  char *image;                          /* header record image */
  char *data;                           /* current data image */
  
  int workmode;                         /* reading or writing */
  jmp_buf trap;                         /* longjump trap point */
  
  long  isrecnum;                       /* current record number */
  int   isreclen;                       /* current record length */
  int   iserrno;                        /* failure code */
  int   iserrio;                        /* what and where */

  long	natcurr;			/* natural order current */

  char  isstat1;                        /* cobol status variables */
  char  isstat2;
  char  isstat3;
  char  isstat4;
#if( ISVARIABLE )  
  char  *vcbuf;				/* vl compression temp buffer */
  int   vclen;				/* vl compression temp len */
#endif
  pid_t ispid;                          /* process id blocking lock attempt */
  };

/* custom details ------------------------------------------------ */

#if( ISCUSTOM == 1 )
# include <iscustom.h>
#endif


/* entry function prototypes ------------------------------------- */

#if( ISDECLARE )
# define ISD3(s) s
#else
# define ISD3(s) ()
#endif
#if( ISHUGE == 0 ) /* no large file support */
# define ISLSEEK   lseek
# define ISOPCALL  open
# define OFFT      long
# define UOFFT     unsigned long

#else  /* hp-ux implementation of large file support */
# define ISLSEEK   lseek64
# define ISOPCALL  open64
# define OFFT      off64_t
# define UOFFT     uint64_t

#endif

#if( ISDATAVOID )
# define ISDD void
#else
# define ISDD char
#endif

#if( ISINTERNAL )
#define ISD1 
#define ISD2
#else
#define ISD1 extern
#define ISD2
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if( ISINTERNAL )
#else
ISD1 char * ISD2 iscopyright;
ISD1 char * ISD2 isversnumber;
ISD1 char * ISD2 is_errlist[];
ISD1 int ISD2 is_nerr;
#endif

ISD1 char isstat1;
ISD1 char isstat2;
ISD1 char isstat3;
ISD1 char isstat4;

ISD1 int ISD2 isLock ISD3((IsFile *isam));
ISD1 int ISD2 isUnLock ISD3((IsFile *isam));
ISD1 int ISD2 isRelease ISD3((IsFile *isam));
ISD1 int ISD2 isRelRec ISD3((IsFile *isam, long recnum));
ISD1 int ISD2 isRelCurr ISD3((IsFile *isam));

ISD1 int ISD2 isThreaded ISD3((void));
ISD1 int ISD2 isAdmDtoI ISD3((IsFile *isam));
ISD1 IsFile * ISD2 isAdmItoD ISD3((int id));
ISD1 int ISD2 isCleanUp ISD3((void));
ISD1 IsFile * ISD2 isAdmTxnLast ISD3((void));

ISD1 IsFile * ISD2 isBuild ISD3((char *name, int dlen, int mlen, IsKdsc *kdsc, int mode));
ISD1 int ISD2 isPrecious ISD3((IsFile *isam, int flag));
ISD1 int ISD2 isAddIndex ISD3((IsFile *isam, IsKdsc *kdsc));
ISD1 int ISD2 isUserInfo ISD3((IsFile *isam, int mode, ISDD *pad));

ISD1 int ISD2 isDelete ISD3((IsFile *isam, ISDD *pad));
ISD1 int ISD2 isDelCurr ISD3((IsFile *isam));
ISD1 int ISD2 isDelRec ISD3((IsFile *isam, long recnum));

ISD1 int ISD2 isErase ISD3((char *name));
ISD1 int ISD2 isRename ISD3((char *oname, char *nname));

ISD1 int ISD2 isDelIndex ISD3((IsFile *isam, struct keydesc *kdsc));

ISD1 int ISD2 isIndexInfo ISD3((IsFile *isam, IsKdsc *kdsc, int idx));
ISD1 int ISD2 isIsamInfo ISD3((IsFile *isam, struct dictinfo *dict));
ISD1 int ISD2 isErrno ISD3((IsFile *isam));
ISD1 int ISD2 isErrio ISD3((IsFile *isam));
ISD1 long ISD2 isRecnum ISD3((IsFile *isam));
ISD1 long ISD2 isReclen ISD3((IsFile *isam));
ISD1 int ISD2 isSetrec ISD3((IsFile *isam, long recnum));
ISD1 int ISD2 isSetlen ISD3((IsFile *isam, short reclen));

ISD1 IsFile * ISD2 isOpen ISD3((char *name, int mode));
ISD1 int ISD2 isClose ISD3((IsFile *isam));
ISD1 int ISD2 isLockCheck ISD3((IsFile *isam, int flag));
ISD1 int ISD2 isSetMode ISD3((IsFile *isam, int mode));

ISD1 IsFile * ISD2 isCluster ISD3((IsFile *isam, IsKdsc *kdsc));
ISD1 IsFile * ISD2 isClone ISD3((IsFile *isam, char *name ));
ISD1 int ISD2 isCopy ISD3((IsFile *dest, IsFile *source, IsKdsc *kdsc));

ISD1 int ISD2 isRead ISD3((IsFile *isam, ISDD *pad, int mode));
ISD1 int ISD2 isStart ISD3((IsFile *isam, IsKdsc *key, int len, ISDD *pad, int mode));
ISD1 int ISD2 isIndex ISD3((IsFile *isam, int idx));
ISD1 int ISD2 isGoto ISD3((IsFile *isam, long recnum));
ISD1 int ISD2 isPush ISD3((IsFile *isam, int *idx, long *rec));
ISD1 int ISD2 isPop ISD3((IsFile *isam, int idx, long rec));
ISD1 int ISD2 isData ISD3((IsFile *isam, ISDD *pad, long recnum));

ISD1 int ISD2 isSetUnique ISD3((IsFile *isam, long value));
ISD1 int ISD2 isUniqueId ISD3((IsFile *isam, long *dest));

ISD1 int ISD2 isGetLastRec ISD3((IsFile *isam, long *last));
ISD1 int ISD2 isSetLastRec ISD3((IsFile *isam, long last));
ISD1 int ISD2 isLastRec ISD3((IsFile *isam, long *last));

ISD1 int ISD2 isRewrite ISD3((IsFile *isam, ISDD *newpad));
ISD1 int ISD2 isRewCurr ISD3((IsFile *isam, ISDD *newpad));
ISD1 int ISD2 isRewRec ISD3((IsFile *isam, long recnum, ISDD *newpad));
ISD1 int ISD2 isRewNxt ISD3((IsFile *isam, ISDD *newpad));

ISD1 int ISD2 isWrite ISD3((IsFile *isam, ISDD *pad));
ISD1 int ISD2 isWrLock ISD3((IsFile *isam, ISDD *pad));
ISD1 int ISD2 isWrCurr ISD3((IsFile *isam, ISDD *pad));

ISD1 int ISD2 isAudit ISD3((IsFile *isam, ISDD *pad, int mode));

ISD1 int ISD2 isTxnInit ISD3((short ( *call )(void) ));
ISD1 int ISD2 isLogOpen ISD3((char *name));
ISD1 int ISD2 isLogClose ISD3((void));
ISD1 int ISD2 isBegin ISD3((void));
ISD1 int ISD2 isCommit ISD3((void));
ISD1 int ISD2 isRollBack ISD3((void));
ISD1 int ISD2 isRecover ISD3((void));
ISD1 int ISD2 isSuspLog ISD3((void));
ISD1 int ISD2 isResumLog ISD3((void));
ISD1 int ISD2 isTxnId ISD3((int value));

ISD1 int ISD2 isCheckData ISD3((IsFile *isam));
ISD1 int ISD2 isCheckIndex ISD3((IsFile *isam, int idx));
ISD1 int ISD2 isRebuildFree ISD3((IsFile *isam, int which));
ISD1 int ISD2 isRebuildIdx ISD3((IsFile *isam, int idx));
#if( ISVARIABLE )
ISD1 int ISD2 isCheckVarlen ISD3((IsFile *isam, struct isVarStat *stats));
#endif

ISD1 void ISD2 isFatal ISD3((void(*call)(char *)));

ISD1 int ISD2 isStartUp ISD3((void));

ISD1 int ISD2 ldInt ISD3((char *pad));
ISD1 int ISD2 stInt ISD3((int value, char *pad));
ISD1 long ISD2 ldLong ISD3((char *pad));
ISD1 int ISD2 stLong ISD3((long value, char *pad));
ISD1 int ISD2 stChar ISD3((char *str, char *pad, int len));
ISD1 int ISD2 ldChar ISD3((char *pad, int len, char *str));
ISD1 float ISD2 ldFloat ISD3((char *pad));     
ISD1 int ISD2 stFloat ISD3((float value, char *pad));
ISD1 double ISD2 ldDbl ISD3((char *pad));     
ISD1 int ISD2 stDbl ISD3((double value, char *pad));
ISD1 int ISD2 stFltNull ISD3((float value, char *pad, short null));
ISD1 float ISD2 ldFltNull ISD3((char *pad, short *null));
ISD1 int ISD2 stDblNull ISD3((double value, char *pad, short null));
ISD1 double ISD2 ldDblNull ISD3((char *pad, short *null));

#ifdef __cplusplus
};
#endif

#if( ISINTERNAL )
#else
# undef ISD1
# undef ISD2
# undef ISD3
# undef ISDD
#endif

/* end header ---------------------------------------------------- */
