home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
CPROG
/
CKEYTREE.ZIP
/
KEYTREE3.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-11
|
45KB
|
1,667 lines
/*AUGUST 1991 version 3.1*/
/****************************************************************************
* *
* KeyTree Utilities *
* *
* Copyright 1991 by Rewse Consultants Limited *
* *
* The KeyTree Utilities are issued as shareware. In case you are unaware *
* of how the shareware system works, it is NOT 'free' software. *
* No initial charge is made for the software, so that you can try it out *
* without obligation. However, if you continue to use the software (and in *
* the case of the KeyTree Utilities, use programs created using them), *
* then you are required to pay a registration fee. To register your use of *
* the KeyTree Utilities, we ask you to pay a miserly £30 (UK Pounds), a *
* mere fraction of the cost that you are saving in time and effort. Please *
* send your registration fee to : *
* *
* Rewse Consultants Limited *
* 44, Horseshoe Road, Pangbourne, Reading, Berkshire RG8 7JL, UK *
*****************************************************************************
* ┌─────────┐ *
* ┌─────┴───┐ │ (R) *
* ──│ │o │────────────────── *
* │ ┌─────┴╨──┐ │ Association of *
* │ │ │─┘ Shareware *
* └───│ o │ Professionals *
* ──────│ ║ │──────────────────── *
* └────╨────┘ MEMBER *
****************************************************************************/
#include "stdio.h"
#include "stdarg.h"
#include "dos.h"
#include "sys\types.h"
#include "sys\stat.h"
#include "fcntl.h"
#include "ctype.h"
#include "stdlib.h"
#include "errno.h"
#define CREATMODE O_RDWR|O_BINARY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE
#define RWMODE O_RDWR|O_BINARY
void __ktseparator()
{ putchar('/'); /* if your compiler supports it, you should replace */
fflush(stdout); /* putchar with putch. The fflush is necessary with */
/* Zortech's compiler, otherwise the screen is not */
/* refreshed until you display a newline. */
}
void __ktputch(char a)
{ putchar(a);
fflush(stdout);
}
void __back()
{ printf("\b \b"); /* replace this command with cprintf */
fflush(stdout);
}
/*#define __HELP ; The ktGet commands (..Key,..Str,..Char,..Press)
recognise when a function key is pressed and will
suspend their operation to call the routine defined
here. Initially set to the null ; , you should
insert the name of your help routine with its
associated parameters, if any, and move the comment
delimiters to after the #def. Your help routine
can find which function key was pressed from the
global integer ktFKEY. The current cursor position
will be automatically preserved. This facility is
particularly useful if you are providing on-line
help screens.
e.g. #define __HELP helpwin(); */
int ktSCAN,ktERRNO,ktFKEY,ktINDEXED;
char ktCHAR;
/* On no account should you attempt to alter any of the following data *
* items in your programs */
typedef struct {int dup,inxct,curinx,inx_entry,access,fd,*keys,minsiz,
curtyp,maxkey,ixdes,hks;
long inx_pos,base,recptr,nexrec,fsize,chain[2],BaseEntry,
start;
char status,filename[60];
int del,maxread;
} _kt_;
_kt_ **_KT_ = NULL,*KT;
struct { long ix;
int en,x;} __alter[10];
union { int a[2];
char b[2*sizeof(int)];} __tmplen;
long __inx_char, __inx[99], lseek(), cur_ind_pos;
int __inx_size[4] = {30,13,40,99},__filect = 0,__function = 0,
__FORWARD, cur_ind_fd;
#define _INDEXED !(KT->status&2)
#define _DELETED KT->status&'\x80'
#define _LOCKED KT->status&1
#define _STATUS KT->status
#define _MAXKEY KT->maxkey
#define _PREVCHAIN KT->chain[0]
#define _NEXTCHAIN KT->chain[1]
#define _FIRSTINDEX -KT->keys[3*KT->curinx]
#define _INDEXSIZE __inx_size[KT->curtyp]
#define _INDEXTYPE(x) KT->keys[3*(x) + 1]
#define _INDEXPARTS(x) KT->keys[3*(x) + 2]
#define ESCAPE (ktSCAN == 1)
#define ENTER (ktSCAN == 28)
/************************************************************************
* *
* Common utilities *
* *
************************************************************************/
int __wrdata(char *ptr,unsigned int len)
{ return(write(KT->fd,ptr,len));
}
int __ktData(char *ptr,unsigned int len)
{ return(read(KT->fd,ptr,len));
}
int __seekdata(long offs)
{ return(lseek(KT->fd,offs,0));
}
void __wrtstatus()
{ __seekdata(KT->recptr);
__wrdata((char *)&_STATUS,1);
}
void __wrt_elem(char *recpt,int y)
{ union {int x[2];
char xc[4];
} q;
__wrtstatus();
q.x[0] = y;
q.x[1] = 0;
if (KT->dup) __wrdata((char *)&_PREVCHAIN,KT->dup);
__wrdata(q.xc,2*sizeof(int)); /*data length*/
__wrdata(recpt,y);
q.x[0] += 3*sizeof(int) + KT->dup + 1;
__wrdata(q.xc,sizeof(int));
KT->fsize += q.x[0];
}
int __FileOpen(int fno)
{ if (fno > 0) { KT = _KT_[--fno];
if (fno < __filect && KT)
{ ktERRNO = 0;
return(1);
}
}
ktERRNO = 9;
return(0);
}
int __FileReady(int fno)
{ if (__FileOpen(fno)) { if (KT->recptr <= 0) ktERRNO = 20;
else { if (_DELETED) ktERRNO = 28;
else return(1);
}
}
return(0);
}
int __oktowrite()
{ if (!KT->access) { ktERRNO = 12;
return(0);
}
return(1);
}
int __locked(int fno)
{ if (!__FileReady(fno) || !__oktowrite()) return(1);
if (_LOCKED) { ktERRNO = 22;
return(1);
}
return(0);
}
int __inx_key(char keychar)
{ int z;
if ((z = (int)keychar) != 0)
{ switch (KT->curtyp)
{ case 0 : if (z == ' ') z = 2;
else if (isalpha(z)) z = toupper(z) - 62;
else z = 1;
break;
case 2 : if (z == ' ') z = 2;
else if (isalpha(z)) z = toupper(z) - 52;
else { z -= 45;
if (z < 3 || z > 12) z = 1;
}
break;
case 1 : if (z < 47 || z > 57) z = 1;
else z -= 46;
break;
case 3 : if (z < 31 || z > 127) z = 1;
else z -= 30;
}
}
return(KT->inx_entry = ++z);
}
va_list __KTap;
int __setupkey(char **key,char *recpt)
{ int x,*y,z,L,S,b;
char *p,*q;
q = *key = malloc(_MAXKEY);
if (!q) { ktERRNO = 7; return(0);}
memset(q,0,_MAXKEY);
y = &KT->keys[KT->ixdes];
z = 0;
for (x = _INDEXPARTS(KT->curinx); x > 0; --x)
{ L = *y++;
S = *y++;
p = (recpt) ? &recpt[S] : va_arg(__KTap,char *);
if (!p) return(0);
strncpy(&q[z],p,L);
b = strlen(&q[z]);
if (b < L) z++;
z += b;
}
return(1);
}
void __readkey(char **ptr)
{ char *trec;
__seekdata(__inx_char);
__ktData(&_STATUS,1);
if (KT->dup) __seekdata(__inx_char + KT->dup + 1);
__ktData(__tmplen.b,2*sizeof(int));
trec = malloc(__tmplen.a[0]);
if (!trec) ktERRNO = 7;
else { __ktData(trec,__tmplen.a[0]);
__setupkey(&(*ptr),trec);
free(trec);
}
}
void __setnamefil(char *ptr1,char *ptr2)
{ strcpy(ptr2,ptr1);
while (*ptr2 && *ptr2 != '.') ++ptr2;
if (!*ptr2) strcpy(ptr2,".fil");
}
int __read_elem(char *recpt)
{ int x;
union { int x[2];
char xc[2*sizeof(int)];
} q;
ktINDEXED = _INDEXED;
if (KT->dup) __ktData((char *)&_PREVCHAIN,KT->dup);
if (__ktData(q.xc,2*sizeof(int)) > 0)
if (q.x[0] > 1)
{ KT->nexrec = KT->recptr + q.x[0] + q.x[1] +
KT->dup + 1 + 3*sizeof(int);
x = (KT->maxread > 0 && q.x[0] > KT->maxread) ?
KT->maxread : q.x[0];
if (__ktData(recpt,x) > 0) return(q.x[0]);
}
ktERRNO = 18;
return(0);
}
int __read_indexed(char *recpt)
{ __seekdata(KT->recptr);
if (__ktData((char *)&_STATUS,1) < 1) { ktERRNO = 18;
return(0);
}
return(__read_elem(recpt));
}
void __next_index(int y)
{ int x,z;
KT->curinx = y;
KT->curtyp = _INDEXTYPE(y);
_MAXKEY = 0;
z = 3*KT->inxct;
for (x = 0; x < y; ++x) z += 2*_INDEXPARTS(x);
KT->ixdes = z;
for (x = _INDEXPARTS(y); x > 0; --x)
{ _MAXKEY += KT->keys[z];
z += 2;
}
}
void __read_inx()
{ if (KT->fd != cur_ind_fd || KT->inx_pos != cur_ind_pos)
{ __seekdata(-KT->inx_pos + 1);
__ktData((char *)__inx,_INDEXSIZE*sizeof(long));
cur_ind_fd = KT->fd;
cur_ind_pos = KT->inx_pos;
}
}
void __wrt_inx()
{ union { char a[2];
int b; } q;
__seekdata(-KT->inx_pos);
q.a[0] = '0' + KT->curinx;
__wrdata(q.a,1);
q.b = _INDEXSIZE*sizeof(long);
__wrdata((char *)__inx,q.b);
if (KT->fsize == -KT->inx_pos)
{ q.b += 1 + sizeof(int);
__wrdata(q.a,sizeof(int));
KT->fsize += q.b;
}
cur_ind_fd = KT->fd;
cur_ind_pos = KT->inx_pos;
}
int __lookup(char *keypt)
{ int x,y,z,k;
KT->inx_pos = _FIRSTINDEX;
y = _MAXKEY;
for (x = k = 0; x < y; ++x)
{ __read_inx();
z = __inx_key(keypt[x]);
if (!__inx[z]) break;
if ((__inx_char = __inx[z]) > 0) { KT->recptr = __inx_char;
k = 1;
break;
}
KT->inx_pos = __inx_char;
}
y = KT->curinx;
__alter[y].ix = KT->inx_pos;
__alter[y].x = x;
__alter[y].en = z;
return(k);
}
void __recordlookup(char *recpt)
{ char *temk;
if (__setupkey(&temk,recpt)) { __lookup(temk);
free(temk);
}
}
int __keysmatch(char *new,char *old)
{ int x,y,z;
char a,b;
for (x = 0; x < _MAXKEY; ++x)
{ a = *new++;
b = *old++;
if (a != b) { z = KT->inx_entry;
/* preserve inx_entry */
y = __inx_key(a) - __inx_key(b);
KT->inx_entry = z;
if (y) return(y);
}
}
return(0);
}
int __Exists(char *keypt)
{ int z;
char *temk;
if (__lookup(keypt)) { __readkey(&temk);
z = __keysmatch(keypt,temk);
free(temk);
if (!z) return(__tmplen.a[0]);
}
return(0);
}
void __update_index(char *recpt,int s)
{ int x,y,k,i;
long q,*inxp,L;
char *oldk,*newk;
L = KT->recptr;
KT->inx_pos = (s) ? _FIRSTINDEX : __alter[KT->curinx].ix;
if (!__setupkey(&newk,recpt)) return;
__read_inx();
if (s) { for (y = 0;; ++y)
{ x = __inx_key(newk[y]);
__inx_char = __inx[x];
if (__inx_char >= 0) break;
KT->inx_pos = __inx_char;
__read_inx();
}
}
else { x = __alter[KT->curinx].en;
y = __alter[KT->curinx].x;
}
__inx_char = __inx[x];
if (__inx_char)
{ __readkey(&oldk);
q = -KT->fsize;
for (; ;++y)
{ k = __inx_key(oldk[y]);
x = __inx_key(newk[y]);
if (k != x) break;
__inx[k] = q;
__wrt_inx();
i = _INDEXSIZE*sizeof(long);
memset((char *)__inx,0,i);
__inx[0] = KT->inx_pos;
KT->inx_pos = q;
q -= (i + sizeof(int) + 1);
}
__inx[k] = __inx_char;
free(oldk);
}
KT->recptr = L;
__inx[x] = KT->recptr;
KT->inx_entry = x;
__wrt_inx();
free(newk);
}
int __oktoadd(char *recpt,int err)
{ int y,z,k,j;
long L;
char *keypt;
z = 1;
k = KT->curinx;
L = KT->recptr;
for (y = 0; y < KT->inxct; ++y)
{ __alter[y].ix = 0;
__next_index(y);
if (!__setupkey(&keypt,recpt)) return(0);
j = __Exists(keypt);
free(keypt);
if (j) { ktERRNO = y + err;
z = 0;
break;
}
}
KT->recptr = L;
__next_index(k);
return(z);
}
/************************************************************************
* *
* 1 ktCreate - create file and write zero filled base indexes *
* *
************************************************************************/
int ktCreate(char *nameptr,int chaining,int indexcount,int *keyptr)
/* chaining 0 - if no chaining
1 - if chaining required
*keyptr ptr to a repeating array of integers
(2 + 2*indexparts)*indexcount
key_type 0 - alphabetic inc. space
1 - numeric plus space
2 - alphanumeric inc. space
3 - printable (32 - 127)
key_length length of key in bytes.
(if <= 0 : no more sections of key)
key_start count of bytes preceding key in record
*/
{ int x,y,z,k,n;
char zz[2];
_kt_ t;
union { char a[2]; int b;}q;
ktERRNO = 13; /* validate parameters */
if (chaining) chaining = 2*sizeof(long);
if (indexcount > 10 || indexcount <= 0) return(0);
for (x = y = k = 0; x < indexcount; ++x)
{ if (keyptr[y] < 0 || keyptr[y] > 3) return(0);
for (;;) { k += 2;
if (keyptr[++y] <= 0) return(0);
if (keyptr[++y] < 0) return(0);
if (keyptr[y + 1] < 0) break;
}
y += 2;
}
__setnamefil(nameptr,t.filename); /* if no ext. add .fil */
if ((t.fd = open((char *)(t.filename),RWMODE,0)) >= 0)
{ close(t.fd); ktERRNO = 1; return(0); }
if ((t.fd = open(t.filename,CREATMODE)) < 0)
{ ktERRNO = (errno == EMFILE) ? 5 : 10; return(0); }
ktERRNO = 0;
t.inxct = indexcount;
t.dup = 19284; /* = 'KT' */
if (chaining) ++t.dup;
t.curinx = (k + 3*indexcount)*sizeof(int);
write(t.fd,(char *)&t,3*sizeof(int));
t.keys = (int *)malloc(t.curinx);
if (!t.keys) { ktERRNO = 7; close(t.fd); return(0);}
n = t.curinx + 3*sizeof(int);
z = 3*indexcount;
for (x = y = 0; x < 3*indexcount; ++x)
{ t.keys[x++] = n;
n += __inx_size[keyptr[y]]*sizeof(long) + 1 + sizeof(int);
t.keys[x++] = keyptr[y++];
t.keys[x] = 0;
for (;;)
{ if (keyptr[y] < 0) break;
t.keys[x]++;
t.keys[z++] = keyptr[y++];
t.keys[z++] = keyptr[y++];
}
++y;
}
y = write(t.fd,(char *)t.keys,t.curinx);
if (y < 1)
{ close(t.fd);
free((char *)t.keys);
return(0);
}
memset((char *)__inx,0,99*sizeof(long));
for (x = 0; x < indexcount; ++x)
{ zz[0] = '0' + x;
write(t.fd,zz,1);
q.b = __inx_size[t.keys[3*x + 1]]*sizeof(long);
write(t.fd,(char *)__inx,q.b);
q.b += 1 + sizeof(int);
write(t.fd,q.a,sizeof(int));
}
close(t.fd);
free((char *)t.keys);
return(1);
}
/************************************************************************
* *
* 2 ktOpen - Open file and read base index *
* *
************************************************************************/
void __set_min_size()
{ int x,y,*z,q,a;
z = &KT->keys[3*KT->inxct];
KT->minsiz = KT->hks = 1;
for (x = 0; x < KT->inxct; ++x)
{ y = KT->keys[3*x + 2];
for (a = 1; a <= y; ++a)
{ q = *z;
z++;
q += *z;
if (*z > KT->hks - 1) KT->hks = *z + 1;
if (KT->minsiz < q) KT->minsiz = q;
z++;
}
}
}
int ktOpen(char *nameptr,int mode,int indno) /* mode : 0 = read only
non-0 = read-write
indno : which index to open */
{ int x,y;
_kt_ **t;
if (indno < 0) { ktERRNO = 4; return(0); }
ktERRNO = 0;
for (y = 0; y < __filect; ++y) if (!_KT_[y]) break;
if (y == __filect)
{ _KT_ = (_kt_ **)realloc(_KT_,(++__filect)*sizeof(_kt_ *));
if (!_KT_) { ktERRNO = 7; return(0); }
}
KT = _KT_[y] = (_kt_ *)malloc(sizeof(_kt_));
if (!_KT_[y]) { ktERRNO = 7; return(0); }
memset((char *)KT,0,sizeof(_kt_));
__setnamefil(nameptr,KT->filename);
if ((KT->fd = open((char *)(KT->filename),RWMODE,0)) < 0)
ktERRNO = (errno == EMFILE) ? 5 :
((errno == EACCES) ? 10 : 2);
else
{ KT->fsize = lseek(KT->fd,0L,2);
if (KT->fsize <= 0) ktERRNO = 6;
else { __seekdata(0L);
__ktData((char *)KT,3*sizeof(int));
x = KT->dup - 19284;
if (x && x != 1 && x != 0x100 && x != 0x101) ktERRNO = 3;
else { KT->dup = x&1;
if (KT->dup) KT->dup = 2*sizeof(long);
if (KT->inxct <= indno) ktERRNO = 4;
else { KT->keys = (int *)malloc(KT->curinx);
if (!KT->keys) ktERRNO = 7;
else { if (__ktData((char *)(KT->keys),KT->curinx) > 0)
{ __next_index(indno);
KT->access = mode;
KT->start = __inx_size[_INDEXTYPE(KT->inxct-1)]*sizeof(long) +
KT->keys[3*KT->inxct - 3] + sizeof(int) + 1;
__set_min_size();
return(y + 1);
}
ktERRNO = 8;
free((char *)(KT->keys));
}
}
}
}
close(KT->fd);
}
free((char *)KT);
_KT_[y] = 0;
return(0);
}
/************************************************************************
* *
* 3 ktChangeIndex - change index *
* *
************************************************************************/
int ktChangeIndex(int fno,int indno)
{ if (!__FileOpen(fno)) return(0);
if (indno < 0 || indno >= KT->inxct) { ktERRNO = 4; return(0); }
if (indno != KT->curinx)
{ __next_index(indno);
KT->BaseEntry = KT->inx_entry = 0;
KT->inx_pos = _FIRSTINDEX;
}
return(1);
}
/************************************************************************
* *
* 4 ktFlush - make sure file is written to disk *
* *
************************************************************************/
int ktFlush(int fno)
{ union REGS regs;
if (!__FileOpen(fno)) return(0);
regs.h.ah = 0x45;
regs.x.bx = KT->fd;
int86(0x21,®s,®s);
if (regs.x.cflag) { close(KT->fd);
KT->fd = open(KT->filename,RWMODE,0);
}
else close(regs.x.ax);
return(1);
}
/************************************************************************
* *
* 5 ktClose - close file *
* *
************************************************************************/
int ktClose(int fno)
{ if (!__FileOpen(fno)) return(0);
close(KT->fd);
free((char *)(KT->keys));
free((char *)KT);
_KT_[fno - 1] = NULL;
return(1);
}
/************************************************************************
* *
* 7 ktAdd - add a record to a file and update indexes *
* *
************************************************************************/
void __add_indexes(char *recpt)
{ int k,y;
k = KT->curinx;
for (y = 0; y < KT->inxct; ++y)
if (y != k) { __next_index(y);
__update_index(recpt,0);
}
__next_index(k);
__update_index(recpt,0);
}
int ktAdd(int fno,void *recpt,int leng)
{ char *areapt;
int x;
if (leng < 1) ktERRNO = 15;
else if (__FileOpen(fno))
{ if (__oktowrite())
{ if (leng < KT->minsiz)
{ areapt = (char *)malloc(KT->minsiz);
memset(areapt,0,KT->minsiz);
memmove(areapt,(char *)recpt,leng);
x = (leng > KT->hks) ? leng : KT->hks;
if (areapt[x-1]) ++x;
}
else { areapt = (char *)recpt;
x = leng;
}
if (__oktoadd(areapt,40))
{ KT->recptr = KT->fsize;
_PREVCHAIN = _NEXTCHAIN = _STATUS = 0;
__wrt_elem(areapt,x);
__add_indexes(areapt);
if (areapt != (char *)recpt) free(areapt);
return(1);
}
if (areapt != (char *)recpt) free(areapt);
KT->recptr = 0;
}
}
return(0);
}
/************************************************************************
* *
* 8 ktAddPhys - add a record to file - do not update index *
* *
************************************************************************/
int ktAddPhys(int fno,void *recpt,int leng)
{ if (leng <= 0) ktERRNO = 15;
else if (__FileOpen(fno))
if (__oktowrite())
{ _PREVCHAIN = _NEXTCHAIN = 0;
KT->recptr = KT->fsize;
_STATUS = 2;
__wrt_elem((char *)recpt,leng);
return(1);
}
return(0);
}
/************************************************************************
* *
* 9 ktRead - read a record with a specific key *
* *
************************************************************************/
int __nn(char *recpt,int b,int errs)
{ int a1,qq;
long y,z,a2,*inxp;
inxp = __inx;
a1 = KT->inx_entry;
a2 = KT->inx_pos;
KT->del = 0;
__read_inx();
for (;;)
{ if (__FORWARD > 0) { ++KT->inx_entry;
qq = (KT->inx_entry >= _INDEXSIZE ||
(!b && KT->inx_pos == KT->base &&
KT->inx_entry != KT->BaseEntry));
}
else { --KT->inx_entry;
qq = (KT->inx_entry <= 0 ||
(!b && KT->inx_pos == KT->base &&
KT->inx_entry != KT->BaseEntry));
}
if (qq)
{ if (KT->inx_pos >= (long)_FIRSTINDEX ||
(!b && KT->inx_pos >= KT->base))
{ ktERRNO = errs;
KT->inx_entry = a1;
KT->inx_pos = a2;
return(0);
}
y = KT->inx_pos;
KT->inx_pos = *inxp;
__read_inx();
for (KT->inx_entry = 1; y != __inx[KT->inx_entry];)
++KT->inx_entry;
continue;
}
if ((z = __inx[KT->inx_entry]) > 0)
{ KT->recptr = z;
return(__read_indexed(recpt));
}
if (z < 0) { KT->inx_pos = z;
__read_inx();
KT->inx_entry =
(__FORWARD > 0) ? 0 : _INDEXSIZE;
}
}
}
int __Find(int fno,char *recpt)
{ int x,y;
char *temk,*oldk;
if (!__FileOpen(fno)) return(0);
ktERRNO = KT->BaseEntry = 0;
if (!__setupkey(&temk,NULL))
{ if (ktERRNO == 7) return(0);
if (!__FORWARD) { ktERRNO = 13; free(temk); return(0); }
}
if (__lookup(temk))
{ y = __read_indexed(recpt);
if (!y) { free(temk);
return(0);
}
if (!__setupkey(&oldk,recpt)) { free(temk);
return(0);
}
x = __keysmatch(temk,oldk);
free(oldk);
if (!x ||
(__FORWARD > 0 && x < 0) ||
(__FORWARD < 0 && x > 0)) { free(temk);
return(y);
}
}
if (!__FORWARD) { ktERRNO = 17;
y = 0;
}
else y = __nn(recpt,1,(__FORWARD > 0) ? 26 : 27);
free(temk);
return(y);
}
int ktRead(int fno,void *recpt,...)
{ int x;
va_start(__KTap,recpt);
__FORWARD = 0;
x = __Find(fno,(char *)recpt);
va_end(__KTap);
return(x);
}
/************************************************************************
* *
* 10 ktReadAfter - read record with key >= a specific key, *
* *
************************************************************************/
int ktReadAfter(int fno,void *recpt,...)
{ int x;
va_start(__KTap,recpt);
__FORWARD = 1;
x = __Find(fno,(char *)recpt);
va_end(__KTap);
return(x);
}
/************************************************************************
* *
* 11 ktReadBefore - read record with key <= a specific key, *
* *
************************************************************************/
int ktReadBefore(int fno,void *recpt,...)
{ int x;
va_start(__KTap,recpt);
__FORWARD = -1;
x = __Find(fno,(char *)recpt);
va_end(__KTap);
return(x);
}
/************************************************************************
* *
* 12 ktLength - check to see if record with a specific key exists *
* & return with the record length if it does *
* set currency to this record but do not read it *
* *
************************************************************************/
int ktLength(int fno,...)
{ int x;
char *temk;
x = __FileOpen(fno);
if (x) { va_start(__KTap,fno);
x = __setupkey(&temk,NULL);
va_end(__KTap);
if (ktERRNO == 7) return(0);
if (!x) ktERRNO = 13;
else { KT->BaseEntry = 0;
x = __Exists(temk);
if (!x) ktERRNO = 17;
}
free(temk);
}
return(x);
}
/************************************************************************
* *
* 13 ktNext - read next logical record *
* *
************************************************************************/
int __ktNext(int fno,void *recpt,int s)
{ if (!__FileOpen(fno)) return(0);
if (!s) KT->recptr = 0;
if (KT->recptr <= 0) { KT->inx_pos = _FIRSTINDEX;
KT->inx_entry = 0;
}
else if (KT->del == 2) --KT->inx_entry;
__FORWARD = 1;
KT->BaseEntry = 0;
return(__nn((char *)recpt,1,26));
}
int ktNext(int fno,void *recpt)
{ return(__ktNext(fno,recpt,1));
}
/************************************************************************
* *
* 14 ktPrev - read previous logical record *
* *
************************************************************************/
int __ktPrev(int fno,void *recpt,int s)
{ if (!__FileOpen(fno)) return(0);
if (!s) KT->recptr = 0;
if (KT->recptr <= 0) { KT->inx_pos = _FIRSTINDEX;
KT->inx_entry = _INDEXSIZE;
}
else if (KT->del == 1) ++KT->inx_entry;
__FORWARD = KT->BaseEntry = 0;
return(__nn((char *)recpt,1,27));
}
int ktPrev(int fno,void *recpt)
{ return(__ktPrev(fno,recpt,1));
}
/************************************************************************
* *
* 15 ktDelete - delete last record read *
* *
************************************************************************/
void __delun(char a)
{ long q,r,s,t, r1[2];
char b;
s = r = _PREVCHAIN;
t = r1[1] = q = _NEXTCHAIN;
if (a == 2) s = t = KT->recptr;
b = _STATUS;
__wrtstatus();
if (KT->dup)
{ if (!r) { _STATUS = a;
for (;r1[1];)
{ __seekdata(r1[1]);
__wrdata((char *)&_STATUS,1);
__ktData((char *)&r1[0],2*sizeof(long));
}
_STATUS = b;
}
else { __seekdata(r + 1 + sizeof(long));
__wrdata((char *)&t,sizeof(long));
if (q) { __seekdata(++q);
__wrdata((char *)&s,sizeof(long));
}
}
}
}
void __index_zero(int k)
{ long L,Q;
int x,y,b;
__inx[KT->inx_entry] = 0;
if (__inx[0])
{ y = b = Q = 0;
for (x = 1; x < _INDEXSIZE; ++x)
if (__inx[x]) { if (++y > 1) break;
Q = __inx[x];
b = (x < KT->inx_entry) ? 1 : 2;
}
if (y < 2 && Q >= 0)
{ for (;y < 2 && __inx[0];)
{ L = KT->inx_pos;
KT->inx_pos = __inx[0];
__read_inx();
for (KT->inx_entry = 1;
L != __inx[KT->inx_entry];)
++KT->inx_entry;
if (KT->BaseEntry && L == KT->base)
{ KT->base = KT->inx_pos;
KT->BaseEntry = KT->inx_entry;
}
__inx[KT->inx_entry] = Q;
y = 0;
for (x = 1; x < _INDEXSIZE; ++x)
{ if (__inx[x]) ++y;
if (y > 1) break;
}
}
if (k == KT->curinx) KT->del = b;
}
}
__wrt_inx();
}
int ktDelete(int fno,void *recpt)
{ int x,k;
char *temk;
if (__locked(fno)) return(0);
_STATUS |= '\x80';
__delun('\x82');
if (_INDEXED)
{ k = KT->curinx;
if (KT->inxct > 1)
{ for (x = 0; x < KT->inxct; ++x)
if (x != k)
{ __next_index(x);
__recordlookup((char *)recpt);
__index_zero(x);
}
__next_index(k);
}
__recordlookup((char *)recpt);
__index_zero(k);
}
return(1);
}
/************************************************************************
* *
* 16 ktUndelete - undelete last physicalrecord read *
* *
************************************************************************/
int ktUndelete(int fno,void *recpt)
{ if (__FileOpen(fno))
{ if (__oktowrite())
{ if (KT->recptr <= 0) ktERRNO = 20;
else { if (_DELETED)
{ if (_INDEXED)
{ if (!__oktoadd((char *)recpt,50)) return(0);
__add_indexes((char *)recpt);
}
_STATUS &= '\x7f';
__delun(2);
return(1);
}
else ktERRNO = 29;
}
}
}
return(0);
}
/************************************************************************
* *
* 17 ktRewrite - rewrite the last record read *
* *
************************************************************************/
union { int a[2]; char b[4]; } __old_length;
struct { long ix;
int en;} __oldix[10];
int __record_moved;
void __alter_index(int y,char *recpt)
{ int x,z;
__next_index(y);
KT->inx_pos = __oldix[y].ix;
KT->inx_entry = __oldix[y].en;
if (KT->inx_pos)
{ __read_inx();
if (__alter[y].ix) { KT->inx_entry = __oldix[y].en;
__index_zero(y);
__update_index(recpt,1);
}
else if (__record_moved)
{ __inx[KT->inx_entry] = KT->recptr;
__wrt_inx();
}
}
}
int ktRewrite(int fno,void *recpt,int length)
{ int x,y,z,i,j,k,e,f;
char *oldk,*keypt,*oldrec,*areapt;
long q,r,s,start;
if (length < 1) { ktERRNO = 15; return(0); }
if (__locked(fno)) return(0);
if (length < KT->minsiz && _INDEXED)
{ areapt = (char *)malloc(KT->minsiz);
memset(areapt,0,KT->minsiz);
memmove(areapt,(char *)recpt,length);
if (length < KT->hks) length = KT->hks;
if (areapt[length-1]) ++length;
}
else areapt = (char *)recpt;
q = KT->recptr;
r = KT->inx_pos;
e = KT->inx_entry;
k = KT->curinx;
start = q + KT->dup + 1;
__seekdata(start);
__ktData(__old_length.b,2*sizeof(int));
__record_moved = (length > __old_length.a[0] + __old_length.a[1]);
if (_INDEXED)
{ __inx_char = q;
z = 1;
f = (__old_length.a[0] > KT->maxkey) ?
__old_length.a[0] : KT->maxkey + 1;
oldrec = malloc(f);
if (!oldrec) { ktERRNO = 7;
if (areapt != (char *)recpt) free(areapt);
return(0);
}
__ktData(oldrec,__old_length.a[0]);
for (y = KT->inxct - 1; y >= 0; --y)
{ __next_index(y);
x = 0;
if (!__setupkey(&keypt,areapt))
{ z = 0; break;}
if (!__setupkey(&oldk,oldrec)) { z = 0; break;}
__oldix[y].ix = __alter[y].ix = 0;
if (__keysmatch(oldk,keypt)) x = __Exists(keypt);
if (!x && (__record_moved || __alter[y].ix))
{
KT->inx_pos = _FIRSTINDEX;
for (j = 0; j < _MAXKEY; ++j)
{ __read_inx();
i = __inx_key(oldk[j]);
if (!__inx[i]) break;
if ((__inx_char = __inx[i]) > 0)
{ KT->recptr = __inx_char;
break;
}
KT->inx_pos = __inx_char;
}
__oldix[KT->curinx].ix = KT->inx_pos;
__oldix[KT->curinx].en = i;
}
free(oldk);
free(keypt);
if (x) { ktERRNO = 30 + y;
z = 0;
break;
}
}
__next_index(k);
free(oldrec);
KT->recptr = q;
KT->inx_pos = r;
KT->inx_entry = e;
if (!z) { if (areapt != (char *)recpt) free(areapt);
return(0);
}
}
if (__record_moved)
{ KT->recptr = q;
_STATUS |= '\x80';
__wrtstatus();
s = KT->recptr = KT->fsize;
_STATUS &= '\x7f';
__wrt_elem(areapt,length);
if (KT->dup)
{ if (_PREVCHAIN)
{ __seekdata(_PREVCHAIN + 1 + sizeof(long));
__wrdata((char *)&s,sizeof(long));
}
if (_NEXTCHAIN)
{ __seekdata(_NEXTCHAIN + 1);
__wrdata((char *)&s,sizeof(long));
}
}
}
else { if (length != __old_length.a[0])
{ __old_length.a[1] += (__old_length.a[0] - length);
__old_length.a[0] = length;
__seekdata(start);
__wrdata(__old_length.b,2*sizeof(int));
}
else __seekdata(start + 2*sizeof(int));
__wrdata(areapt,length);
}
if (_INDEXED) { for (y = 0; y < KT->inxct; ++y)
if (y != k) __alter_index(y,areapt);
__alter_index(k,areapt);
}
if (areapt != (char *)recpt) free(areapt);
return(length);
}
/************************************************************************
* *
* 18 ktGetChar - get character from keyboard *
* *
************************************************************************/
char __runch = 0,__runsc = 0;
char ktGetChar()
{ int d;
union REGS regs;
if (__runch || __runsc) { ktCHAR = __runch;
ktSCAN = __runsc;
__runch = __runsc = 0;
}
else for (;;)
{ regs.x.ax = 0;
int86(0x16,®s,®s);
ktSCAN = regs.h.ah;
ktCHAR = regs.h.al;
if (ktSCAN < 59 || ktSCAN > 68 || __function) break;
#ifdef __HELP
regs.x.ax = 0x300;
regs.x.bx = 0;
int86(0x10,®s,®s);
d = regs.x.dx;
ktFKEY = ktSCAN - 58;
__function = 1;
__HELP
__function = 0;
regs.x.dx = d;
regs.x.ax = 0x200;
regs.x.bx = 0;
int86(0x10,®s,®s);
#else
break;
#endif
}
return(ktCHAR);
}
/************************************************************************
* *
* 19 ktGetPress - get character from keyboard *
* but do not remove it from the buffer *
* *
************************************************************************/
char ktGetPress()
{ __runch = ktGetChar();
__runsc = ktSCAN;
return(__runch);
}
/************************************************************************
* *
* 20 ktGetStr - get string from keyboard *
* *
************************************************************************/
int ktGetStr(char *dataptr,int maxlen)
{ unsigned char a;
int x;
if (!maxlen) maxlen = -1;
for (x = 0;;)
{ a = ktGetChar();
if (ktSCAN == 1 || a == 13) break;
if (ktSCAN == 14)
{ if (x > 0) { dataptr[--x] = 0;
__back();
}
}
else { if (!a) { if (ktSCAN == 75 && x)
{ --x; __ktputch(8); }
else if (ktSCAN == 77 && x < maxlen)
{ if (!dataptr[x]) dataptr[x] = ' ';
__ktputch(dataptr[x++]);
}
}
else { if (x >= maxlen) break;
if (a > 31) { dataptr[x++] = a;
__ktputch(a);
}
}
}
}
dataptr[x] = 0;
return(x);
}
/************************************************************************
* *
* 21 ktGetKey - get key from keyboard and read record *
* *
************************************************************************/
int __found;
int __get_next_part(int k,char *recpt,char *keypt)
{ int x,y,z,l;
char a;
long q;
y = 1;
l = KT->keys[KT->ixdes + 2*k];
if (keypt) memset(keypt,0,l);
for (x = 0; x < l;)
{ a = ktGetChar();
if (ktSCAN == 14 || (!a && ktSCAN == 75))
{ if (x) { --x;
if (keypt) keypt[x] = 0;
__back();
if (!x) KT->inx_pos = _FIRSTINDEX;
else { KT->inx_pos = q;
__read_inx();
q = __inx[0];
}
}
}
else { if ESCAPE return(0);
if ENTER a = 0;
else { if (a < 32) continue;
__ktputch(a);
}
if (keypt) keypt[x] = a;
x++;
__read_inx();
z = __inx_key(a);
if ((__inx_char = __inx[z]) > 0)
{ KT->recptr = __inx_char;
y = __read_indexed(recpt);
__found = 1;
break;
}
if (!__inx_char) return(((a) ? 0 : -1));
q = KT->inx_pos;
KT->inx_pos = __inx_char;
if (!a) return(1);
}
}
return(y);
}
int ktGetKey(int fno,void *recpt,...)
{ int y,k;
char *keypt;
y = __FileOpen(fno);
va_start(__KTap,recpt);
for (k = 0; k < _INDEXPARTS(KT->curinx); ++k)
{ keypt = va_arg(__KTap,char *);
if (!keypt) break;
keypt[0] = 0;
}
va_end(__KTap);
if (y) { keypt = recpt;
va_start(__KTap,recpt);
KT->inx_pos = _FIRSTINDEX;
KT->recptr = KT->BaseEntry = KT->del = 0;
for (k = 0; k < _INDEXPARTS(KT->curinx); ++k)
{ __found = 0;
if (keypt) keypt = va_arg(__KTap,char *);
y = __get_next_part(k,(char *)recpt,keypt);
if (__found || y <= 0) break;
__ktseparator();
}
va_end(__KTap);
}
return(y);
}
/************************************************************************
* *
* 22 ktReadAll - get first record whose key matches the mask *
* *
************************************************************************/
int ktReadAll(int fno,void *recpt,...)
{ int x,y,z;
char *tkey,*okey;
if (!__FileOpen(fno)) return(0);
va_start(__KTap,recpt);
x = __setupkey(&tkey,NULL);
va_end(__KTap);
if (!x && ktERRNO) return(0);
KT->BaseEntry = 1;
KT->inx_pos = _FIRSTINDEX;
KT->base = -1;
for (y = _MAXKEY; !tkey[y-1] && y;) --y;
for (x = 0; x < y; ++x)
{ KT->base = KT->inx_pos;
__read_inx();
z = __inx_key(tkey[x]);
if (!__inx[z]) { KT->BaseEntry = 0;
free(tkey);
ktERRNO = 17;
return(0);
}
KT->BaseEntry = KT->inx_entry = z;
__inx_char = __inx[z];
if (__inx_char > 0)
{ KT->recptr = __inx_char;
z = __read_indexed((char *)recpt);
if (z) { __setupkey(&okey,(char *)recpt);
for (; x < y ; ++x)
{ if (__inx_key(tkey[x]) !=
__inx_key( okey[x]))
{ KT->BaseEntry = 0;
z = 0;
ktERRNO = 17;
break;
}
}
free(okey);
}
free(tkey);
return(z);
}
KT->inx_pos = __inx_char;
}
KT->inx_entry = 0;
__FORWARD = 1;
free(tkey);
return(__nn((char *)recpt,0,0));
}
/************************************************************************
* *
* 23 ktNextAll - get next record whose key matches the mask *
* which was given in the preceding ktReadAll *
* *
************************************************************************/
int __FileBase(void *recpt,int fno)
{ if (__FileOpen(fno))
{ if (KT->BaseEntry && KT->base < 0)
{ if (KT->del && (KT->base > KT->inx_pos ||
KT->inx_entry == KT->BaseEntry))
{ if (__FORWARD)
{ if (KT->del == 2) --KT->inx_entry;
}
else { if (KT->del == 1) ++KT->inx_entry;
}
}
return(__nn((char *)recpt,0,0));
}
else ktERRNO = ((KT->BaseEntry) ? 0 : 25);
}
return(0);
}
int ktNextAll(int fno,void *recpt)
{ __FORWARD = 1;
return(__FileBase(recpt,fno));
}
/************************************************************************
* *
* 24 ktPrevAll - get previous record whose key matches the mask *
* which was given in the preceding ktReadAll *
* *
************************************************************************/
int ktPrevAll(int fno,void *recpt)
{ __FORWARD = 0;
return(__FileBase(recpt,fno));
}
/************************************************************************
* *
* 25 ktAddChain - add new record chained to the current record *
* *
************************************************************************/
int ktAddChain(int fno,void *recpt,int leng)
{ long q,r;
if (!__FileReady(fno)) return(0);
if (!KT->dup) { ktERRNO = 23;
return(0);
}
if (!__oktowrite()) return(0);
if (leng < 1) { ktERRNO = 15; return(0); }
q = KT->fsize;
__seekdata(KT->recptr + 1 + sizeof(long));
__wrdata((char *)&q,sizeof(long));
r = _NEXTCHAIN;
if (r) { __seekdata(++r);
__wrdata((char *)&q,sizeof(long));
}
_PREVCHAIN = KT->recptr;
KT->recptr = q;
_STATUS = 2;
__wrt_elem((char *)recpt,leng);
return(1);
}
/************************************************************************
* *
* 26 ktNextChain - read next record chained to the current record *
* *
************************************************************************/
int __NChain(void *recpt,int fno,int n)
{ long q;
if (__FileOpen(fno))
{ if (!KT->dup) ktERRNO = 23;
else { if (KT->recptr <= 0) ktERRNO = 20;
else { if (_DELETED && !KT->chain[0]) ktERRNO = 28;
else { q = KT->chain[n];
if (q) { KT->recptr = q;
__seekdata(q);
__ktData((char *)&_STATUS,1);
return(__read_elem((char *)recpt));
}
}
}
}
}
return(0);
}
int ktNextChain(int fno,void *recpt)
{ return(__NChain(recpt,fno,1));
}
/************************************************************************
* *
* 27 ktPrevChain - read previous record chained to the current record*
* *
************************************************************************/
int ktPrevChain(int fno,void *recpt)
{ return(__NChain(recpt,fno,0));
}
/************************************************************************
* *
* 28 ktStart - read first logical record in the file *
* *
************************************************************************/
int ktStart(int fno,void *recpt)
{ return(__ktNext(fno,recpt,0));
}
/************************************************************************
* *
* 29 ktEnd - read last logical record in the file *
* *
************************************************************************/
int ktEnd(int fno,void *recpt)
{ return(__ktPrev(fno,recpt,0));
}
/************************************************************************
* *
* 30 ktNextPhys - read next physical record *
* *
************************************************************************/
int __record_status()
{ __seekdata(KT->recptr);
__ktData((char *)&_STATUS,1);
ktINDEXED = _INDEXED;
return (_STATUS < '0' || _STATUS > '9');
}
int __ktNextPhys(int fno,void *recpt,int s)
{ int y;
if (!__FileOpen(fno)) return(0);
if (!s) KT->recptr = 0;
KT->recptr = (KT->recptr <= 0) ? KT->start : KT->nexrec;
for (;;)
{ if (KT->recptr >= KT->fsize)
{ ktERRNO = 19; return(0); }
if (__record_status()) break;
KT->recptr += 1 + sizeof(int) +
__inx_size[_INDEXTYPE(_STATUS-'0')]*sizeof(long);
}
y = __read_elem((char *)recpt);
return( ((_DELETED) ? -y : y));
}
int ktNextPhys(int fno,void *recpt)
{ return(__ktNextPhys(fno,recpt,1));
}
/************************************************************************
* *
* 31 ktPrevPhys - read previous physical record *
* *
************************************************************************/
int __PrevPhys(char *recpt,int fno,int s)
{ int z;
if (!__FileOpen(fno)) return(0);
if (!s) KT->recptr = 0;
if (KT->recptr <= 0) KT->recptr = KT->fsize;
for (;;)
{ if (KT->recptr <= KT->start) { ktERRNO = 21; return(0); }
__seekdata(KT->recptr - (long)sizeof(int));
__ktData((char *)&z,sizeof(int));
KT->recptr -= z;
if (__record_status()) break;
}
z = __read_elem((char *)recpt);
return( ((_DELETED) ? -z : z));
}
int ktPrevPhys(int fno,void *recpt)
{ return(__PrevPhys((char *)recpt,fno,1));
}
/************************************************************************
* *
* 32 ktStartPhys - read first physical record in the file *
* *
************************************************************************/
int ktStartPhys(int fno,void *recpt)
{ return(__ktNextPhys(fno,recpt,0));
}
/************************************************************************
* *
* 33 ktEndPhys - read last physical record in the file *
* *
************************************************************************/
int ktEndPhys(int fno,void *recpt)
{ return(__PrevPhys((char *)recpt,fno,0));
}
/************************************************************************
* *
* 34 ktLock - lock last record read *
* *
************************************************************************/
char __FirstChar(int y,int fno)
{ if (!__FileReady(fno)) return(0);
_STATUS = (_STATUS&254)|y;
__wrtstatus();
ktFlush(fno);
return(1);
}
int ktLock(int fno)
{ return(__FirstChar(1,fno));
}
/************************************************************************
* *
* 35 ktUnlock - unlock last record read *
* *
************************************************************************/
int ktUnlock(int fno)
{ return(__FirstChar(0,fno));
}
/************************************************************************
* *
* 36 ktLocked - returns true if record exists and is locked *
* *
************************************************************************/
int ktLocked(int fno,...)
{ char x[2],*temk;
int k;
if (__FileOpen(fno)) { va_start(__KTap,fno);
k = __setupkey(&temk,NULL);
va_end(__KTap);
if (!k) ktERRNO = 13;
else { k = __Exists(temk);
if (!k) ktERRNO = 17;
else k = _LOCKED;
}
free(temk);
}
return(k);
}
/************************************************************************
* *
* 37 ktSize - returns the size of the file in bytes *
* *
************************************************************************/
long ktSize(int fno)
{ if (!__FileOpen(fno)) return(0L);
return(KT->fsize);
}
/************************************************************************
* *
* 38 ktRecords - returns the size of the file in records *
* *
************************************************************************/
long ktRecords(int fno,int typ)
{ long x,l;
char a[8],b,c;
if (!__FileOpen(fno)) return(0L);
l = KT->start;
for (x = 0;l < KT->fsize;)
{ __seekdata(l);
__ktData(a,1);
if (a[0] >= '0' && a[0] <= '9')
l += __inx_size[_INDEXTYPE(a[0] - '0')]*sizeof(long)
+ 1 + sizeof(int);
else { b = a[0] & 0x80;
if (!typ || (typ > 0 && !b) || (typ < 0 && b))
++x;
if (KT->dup) __ktData(a,KT->dup);
__ktData(__tmplen.b,2*sizeof(int));
l += 1 + KT->dup + 3*sizeof(int) +
__tmplen.a[0] + __tmplen.a[1];
}
}
return(x);
}
/************************************************************************
* *
* 39 ktMaxRead - sets the maximum number of bytes for any read *
* *
************************************************************************/
int ktMaxRead(int fno,int max)
{ if (__FileOpen(fno)) { if (max < 0 || (max > 0 && max < KT->minsiz))
ktERRNO = 15;
else { KT->maxread = max;
return(KT->minsiz);
}
}
return(0);
}