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 >
C/C++ Source or Header  |  1992-05-11  |  45KB  |  1,667 lines

  1. /*AUGUST   1991                             version 3.1*/
  2.  
  3. /****************************************************************************
  4. *                                        *
  5. *    KeyTree Utilities                            *
  6. *                                        *
  7. *    Copyright 1991 by Rewse Consultants Limited                *
  8. *                                        *
  9. *  The KeyTree Utilities are issued as shareware. In case you are unaware   *
  10. *  of how the shareware system works, it is NOT 'free' software.        *
  11. *  No initial charge is made for the software, so that you can try it out   *
  12. *  without obligation. However, if you continue to use the software (and in *
  13. *  the case of the KeyTree Utilities, use programs created using them),     *
  14. *  then you are required to pay a registration fee. To register your use of *
  15. *  the KeyTree Utilities, we ask you to pay a miserly £30 (UK Pounds), a    *
  16. *  mere fraction of the cost that you are saving in time and effort. Please *
  17. *  send your registration fee to :                        *
  18. *                                        *
  19. *    Rewse Consultants Limited                        *
  20. *    44, Horseshoe Road, Pangbourne, Reading, Berkshire RG8 7JL, UK      *
  21. *****************************************************************************
  22. *              ┌─────────┐                                                  *
  23. *        ┌─────┴───┐     │              (R)                                 *
  24. *      ──│         │o    │──────────────────                                *
  25. *        │   ┌─────┴╨──┐ │  Association of                                  *
  26. *        │   │         │─┘  Shareware                                       *
  27. *        └───│    o    │    Professionals                                   *
  28. *      ──────│    ║    │────────────────────                                *
  29. *            └────╨────┘    MEMBER                                          *
  30. ****************************************************************************/
  31. #include "stdio.h"
  32. #include "stdarg.h"
  33. #include "dos.h"
  34. #include "sys\types.h"
  35. #include "sys\stat.h"
  36. #include "fcntl.h"
  37. #include "ctype.h"
  38. #include "stdlib.h"
  39. #include "errno.h"
  40. #define CREATMODE O_RDWR|O_BINARY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE
  41. #define RWMODE O_RDWR|O_BINARY
  42. void    __ktseparator()
  43. {    putchar('/');    /* if your compiler supports it, you should replace */
  44.     fflush(stdout);    /* putchar with putch. The fflush is necessary with */
  45.             /* Zortech's compiler, otherwise the screen is not  */
  46.             /* refreshed until you display a newline.        */
  47. }
  48. void    __ktputch(char a)
  49. {    putchar(a);
  50.     fflush(stdout);
  51. }
  52. void    __back()
  53. {    printf("\b \b"); /* replace this command with cprintf */
  54.     fflush(stdout);
  55. }
  56. /*#define __HELP ;      The ktGet commands (..Key,..Str,..Char,..Press)
  57.               recognise when a function key is pressed and will
  58.               suspend their operation to call the routine defined
  59.               here. Initially set to the null ; , you should 
  60.               insert the name of your help routine with its 
  61.               associated parameters, if any, and move the comment
  62.               delimiters to after the #def. Your help routine
  63.               can find which function key was pressed from the
  64.               global integer ktFKEY. The current cursor position
  65.               will be automatically preserved. This facility is
  66.               particularly useful if you are providing on-line
  67.               help screens.
  68.  
  69.               e.g. #define __HELP helpwin();                   */
  70.  
  71. int    ktSCAN,ktERRNO,ktFKEY,ktINDEXED;
  72. char    ktCHAR;
  73.  
  74. /* On no account should you attempt to alter any of the following data  *
  75.  * items in your programs                                               */
  76.  
  77. typedef struct {int    dup,inxct,curinx,inx_entry,access,fd,*keys,minsiz,
  78.             curtyp,maxkey,ixdes,hks;
  79.         long    inx_pos,base,recptr,nexrec,fsize,chain[2],BaseEntry,
  80.             start;
  81.         char    status,filename[60];
  82.         int    del,maxread;
  83.     } _kt_;
  84. _kt_ **_KT_ = NULL,*KT;
  85.  
  86. struct    { long    ix;
  87.       int    en,x;} __alter[10];
  88.  
  89. union    { int    a[2];
  90.       char    b[2*sizeof(int)];}    __tmplen;
  91. long    __inx_char, __inx[99], lseek(), cur_ind_pos;
  92.  
  93. int    __inx_size[4] = {30,13,40,99},__filect = 0,__function = 0,
  94.     __FORWARD, cur_ind_fd;
  95. #define    _INDEXED    !(KT->status&2)
  96. #define    _DELETED    KT->status&'\x80'
  97. #define    _LOCKED        KT->status&1
  98. #define    _STATUS        KT->status
  99. #define    _MAXKEY        KT->maxkey
  100. #define _PREVCHAIN    KT->chain[0]
  101. #define _NEXTCHAIN    KT->chain[1]
  102. #define _FIRSTINDEX    -KT->keys[3*KT->curinx]
  103. #define _INDEXSIZE    __inx_size[KT->curtyp]
  104. #define _INDEXTYPE(x)    KT->keys[3*(x) + 1]
  105. #define _INDEXPARTS(x)    KT->keys[3*(x) + 2]
  106. #define ESCAPE (ktSCAN == 1)
  107. #define ENTER  (ktSCAN == 28)
  108. /************************************************************************
  109. *                                    *
  110. *    Common utilities                        *
  111. *                                    *
  112. ************************************************************************/
  113.  
  114. int    __wrdata(char *ptr,unsigned int len)
  115. {    return(write(KT->fd,ptr,len));
  116. }
  117. int    __ktData(char *ptr,unsigned int len)
  118. {    return(read(KT->fd,ptr,len));
  119. }
  120. int    __seekdata(long offs)
  121. {    return(lseek(KT->fd,offs,0));
  122. }
  123. void    __wrtstatus()
  124. {    __seekdata(KT->recptr);
  125.     __wrdata((char *)&_STATUS,1);
  126. }
  127. void    __wrt_elem(char *recpt,int y)
  128. {    union {int x[2];
  129.            char xc[4];
  130.           } q;
  131.  
  132.     __wrtstatus();
  133.     q.x[0] = y;
  134.     q.x[1] = 0;
  135.     if (KT->dup) __wrdata((char *)&_PREVCHAIN,KT->dup);
  136.     __wrdata(q.xc,2*sizeof(int));        /*data length*/
  137.     __wrdata(recpt,y);
  138.     q.x[0] += 3*sizeof(int) + KT->dup + 1;
  139.     __wrdata(q.xc,sizeof(int));
  140.     KT->fsize +=  q.x[0];
  141. }
  142. int __FileOpen(int fno)
  143. {    if (fno > 0)    { KT = _KT_[--fno];
  144.               if (fno < __filect && KT)
  145.                 { ktERRNO = 0;
  146.                   return(1);
  147.                 }
  148.             }
  149.     ktERRNO = 9;
  150.     return(0);
  151. }
  152. int    __FileReady(int fno)
  153. {    if (__FileOpen(fno))    { if (KT->recptr <= 0)    ktERRNO = 20;
  154.                   else { if (_DELETED)    ktERRNO = 28;
  155.                      else return(1);
  156.                        }
  157.                 }
  158.     return(0);
  159. }
  160. int __oktowrite()
  161. {    if (!KT->access)    { ktERRNO = 12;
  162.                   return(0);
  163.                 }
  164.     return(1);
  165. }
  166. int    __locked(int fno)
  167. {    if (!__FileReady(fno) || !__oktowrite()) return(1);
  168.     if (_LOCKED)    { ktERRNO = 22;
  169.               return(1);
  170.             }
  171.     return(0);
  172. }
  173. int    __inx_key(char keychar)
  174. {    int z;
  175.     if ((z = (int)keychar) != 0)
  176.         { switch (KT->curtyp)
  177.             { case 0 : if (z == ' ') z = 2;
  178.                    else if (isalpha(z)) z = toupper(z) - 62;
  179.                    else z = 1;
  180.                    break;
  181.               case 2 : if (z == ' ') z = 2;
  182.                    else if (isalpha(z)) z = toupper(z) - 52;
  183.                    else { z -= 45;
  184.                       if (z < 3 || z > 12) z = 1;
  185.                     }
  186.                    break;
  187.               case 1 : if (z < 47 || z > 57) z = 1;
  188.                    else z -= 46;
  189.                    break;
  190.               case 3 : if (z < 31 || z > 127) z = 1;
  191.                    else z -= 30;
  192.             }
  193.         }
  194.     return(KT->inx_entry = ++z);
  195. }
  196. va_list __KTap;
  197. int    __setupkey(char **key,char *recpt)
  198. {    int x,*y,z,L,S,b;
  199.     char *p,*q;
  200.  
  201.     q = *key = malloc(_MAXKEY);
  202.     if (!q) { ktERRNO = 7; return(0);}
  203.     memset(q,0,_MAXKEY);
  204.     y = &KT->keys[KT->ixdes];
  205.     z = 0;
  206.     for (x = _INDEXPARTS(KT->curinx); x > 0; --x)
  207.         { L = *y++;
  208.           S = *y++;
  209.           p = (recpt) ? &recpt[S] : va_arg(__KTap,char *);
  210.           if (!p) return(0);
  211.           strncpy(&q[z],p,L);
  212.           b = strlen(&q[z]);
  213.           if (b < L) z++;
  214.           z += b;
  215.         }
  216.     return(1);
  217. }
  218. void    __readkey(char **ptr)
  219. {    char *trec;
  220.  
  221.     __seekdata(__inx_char);
  222.     __ktData(&_STATUS,1);
  223.     if (KT->dup) __seekdata(__inx_char + KT->dup + 1);
  224.     __ktData(__tmplen.b,2*sizeof(int));
  225.     trec = malloc(__tmplen.a[0]);
  226.     if (!trec) ktERRNO = 7;
  227.     else    { __ktData(trec,__tmplen.a[0]);
  228.           __setupkey(&(*ptr),trec);
  229.           free(trec);
  230.         }
  231. }
  232. void    __setnamefil(char *ptr1,char *ptr2)
  233. {    strcpy(ptr2,ptr1);
  234.     while (*ptr2 && *ptr2 != '.') ++ptr2;
  235.     if (!*ptr2) strcpy(ptr2,".fil");
  236. }
  237. int    __read_elem(char *recpt)
  238. {    int x;
  239.     union { int x[2];
  240.         char xc[2*sizeof(int)];
  241.           } q;
  242.     ktINDEXED = _INDEXED;
  243.     if (KT->dup) __ktData((char *)&_PREVCHAIN,KT->dup);
  244.     if (__ktData(q.xc,2*sizeof(int)) > 0)
  245.          if (q.x[0] > 1)
  246.         { KT->nexrec = KT->recptr + q.x[0] + q.x[1] +
  247.                     KT->dup + 1 + 3*sizeof(int);
  248.           x = (KT->maxread > 0 && q.x[0] > KT->maxread) ?
  249.             KT->maxread : q.x[0];
  250.           if (__ktData(recpt,x) > 0) return(q.x[0]);
  251.         }
  252.     ktERRNO = 18;
  253.     return(0);
  254. }
  255. int    __read_indexed(char *recpt)
  256. {    __seekdata(KT->recptr);
  257.     if (__ktData((char *)&_STATUS,1) < 1)    { ktERRNO = 18;
  258.                           return(0);
  259.                         }
  260.     return(__read_elem(recpt));
  261. }
  262. void __next_index(int y)
  263. {    int x,z;
  264.  
  265.     KT->curinx = y;
  266.     KT->curtyp = _INDEXTYPE(y);
  267.     _MAXKEY = 0;
  268.     z = 3*KT->inxct;
  269.     for (x = 0; x < y; ++x) z += 2*_INDEXPARTS(x);
  270.     KT->ixdes = z;
  271.     for (x =  _INDEXPARTS(y); x > 0; --x)
  272.         { _MAXKEY += KT->keys[z];
  273.           z += 2;
  274.         }
  275. }
  276. void __read_inx()
  277. {      if (KT->fd != cur_ind_fd || KT->inx_pos != cur_ind_pos)
  278.         { __seekdata(-KT->inx_pos + 1);
  279.           __ktData((char *)__inx,_INDEXSIZE*sizeof(long));
  280.           cur_ind_fd = KT->fd;
  281.           cur_ind_pos = KT->inx_pos;
  282.                 }
  283. }
  284. void __wrt_inx()
  285. {    union { char a[2];
  286.         int b; } q;
  287.     __seekdata(-KT->inx_pos);
  288.     q.a[0] = '0' + KT->curinx;
  289.     __wrdata(q.a,1);
  290.     q.b = _INDEXSIZE*sizeof(long);
  291.     __wrdata((char *)__inx,q.b);
  292.     if (KT->fsize == -KT->inx_pos)
  293.         { q.b += 1 + sizeof(int);
  294.           __wrdata(q.a,sizeof(int));
  295.           KT->fsize += q.b;
  296.         }
  297.     cur_ind_fd = KT->fd;
  298.     cur_ind_pos = KT->inx_pos;
  299. }
  300. int    __lookup(char *keypt)
  301. {    int x,y,z,k;
  302.  
  303.     KT->inx_pos = _FIRSTINDEX;
  304.     y = _MAXKEY;
  305.     for (x = k = 0; x < y; ++x)
  306.         { __read_inx();
  307.           z = __inx_key(keypt[x]);
  308.           if (!__inx[z]) break;
  309.           if ((__inx_char = __inx[z]) > 0) { KT->recptr = __inx_char;
  310.                              k = 1;
  311.                              break;
  312.                            }
  313.           KT->inx_pos = __inx_char;
  314.         }
  315.     y = KT->curinx;
  316.     __alter[y].ix = KT->inx_pos;
  317.     __alter[y].x  = x;
  318.     __alter[y].en = z;
  319.     return(k);
  320. }
  321. void    __recordlookup(char *recpt)
  322. {    char *temk;
  323.     if (__setupkey(&temk,recpt))    { __lookup(temk);
  324.                       free(temk);
  325.                     }
  326. }
  327. int    __keysmatch(char *new,char *old)
  328. {    int x,y,z;
  329.     char a,b;
  330.  
  331.     for (x = 0; x < _MAXKEY; ++x)
  332.             { a = *new++;
  333.               b = *old++;
  334.               if (a != b)    { z = KT->inx_entry;
  335.                         /* preserve inx_entry */
  336.                       y = __inx_key(a) - __inx_key(b);
  337.                       KT->inx_entry = z;
  338.                       if (y) return(y);
  339.                     }
  340.             }
  341.     return(0);
  342. }
  343. int    __Exists(char *keypt)
  344. {    int z;
  345.     char *temk;
  346.  
  347.     if (__lookup(keypt))    { __readkey(&temk);
  348.                   z = __keysmatch(keypt,temk);
  349.                   free(temk);
  350.                   if (!z) return(__tmplen.a[0]);
  351.                 }
  352.     return(0);
  353. }
  354. void    __update_index(char *recpt,int s)
  355. {    int x,y,k,i;
  356.     long q,*inxp,L;
  357.     char    *oldk,*newk;
  358.  
  359.     L = KT->recptr;
  360.     KT->inx_pos = (s) ? _FIRSTINDEX : __alter[KT->curinx].ix;
  361.     if (!__setupkey(&newk,recpt)) return;
  362.     __read_inx();
  363.     if (s)    { for (y = 0;; ++y)
  364.             { x = __inx_key(newk[y]);
  365.               __inx_char = __inx[x];
  366.               if (__inx_char >= 0) break;
  367.               KT->inx_pos = __inx_char;
  368.               __read_inx();
  369.             }
  370.         }
  371.     else     { x = __alter[KT->curinx].en;
  372.           y = __alter[KT->curinx].x;
  373.         }
  374.     __inx_char = __inx[x];
  375.     if (__inx_char)
  376.         { __readkey(&oldk);
  377.           q = -KT->fsize;
  378.           for (;  ;++y)
  379.             { k = __inx_key(oldk[y]);
  380.               x = __inx_key(newk[y]);
  381.               if (k != x) break;
  382.               __inx[k] = q;
  383.               __wrt_inx();
  384.               i = _INDEXSIZE*sizeof(long);
  385.               memset((char *)__inx,0,i);
  386.               __inx[0] = KT->inx_pos;
  387.               KT->inx_pos = q;
  388.               q -= (i + sizeof(int) + 1);
  389.             }
  390.           __inx[k] = __inx_char;
  391.           free(oldk);
  392.         }
  393.     KT->recptr = L;
  394.     __inx[x] = KT->recptr;
  395.     KT->inx_entry = x;
  396.     __wrt_inx();
  397.     free(newk);
  398. }
  399. int    __oktoadd(char *recpt,int err)
  400. {    int y,z,k,j;
  401.     long L;
  402.     char *keypt;
  403.  
  404.     z = 1;
  405.     k = KT->curinx;
  406.     L = KT->recptr;
  407.     for (y = 0; y < KT->inxct; ++y)
  408.         { __alter[y].ix = 0;
  409.           __next_index(y);
  410.           if (!__setupkey(&keypt,recpt)) return(0);
  411.           j = __Exists(keypt);
  412.           free(keypt);
  413.           if (j)    { ktERRNO = y + err;
  414.                   z = 0;
  415.                   break;
  416.                 }
  417.         }
  418.     KT->recptr = L;
  419.     __next_index(k);
  420.     return(z);
  421. }
  422. /************************************************************************
  423. *                                    *
  424. * 1    ktCreate - create file and write zero filled base indexes    *
  425. *                                    *
  426. ************************************************************************/
  427.  
  428. int ktCreate(char *nameptr,int chaining,int indexcount,int *keyptr)
  429.  
  430.     /* chaining        0 - if no chaining
  431.                 1 - if chaining required
  432.  
  433.        *keyptr        ptr to a repeating array of integers
  434.                     (2 + 2*indexparts)*indexcount
  435.         key_type    0 - alphabetic inc. space
  436.                 1 - numeric plus space
  437.                 2 - alphanumeric inc. space
  438.                 3 - printable (32 - 127)
  439.         key_length    length of key in bytes.
  440.                 (if <= 0 : no more sections of key)
  441.         key_start    count of bytes preceding key in record
  442.     */
  443. {    int x,y,z,k,n;
  444.     char zz[2];
  445.     _kt_ t;
  446.     union { char a[2]; int b;}q;
  447.  
  448.     ktERRNO = 13;                              /* validate parameters */
  449.     if (chaining) chaining = 2*sizeof(long);
  450.     if (indexcount > 10 || indexcount <= 0) return(0);
  451.     for (x = y = k = 0; x < indexcount; ++x)
  452.         { if (keyptr[y] < 0 || keyptr[y] > 3) return(0);
  453.           for (;;)    { k += 2;
  454.                   if (keyptr[++y] <= 0) return(0);
  455.                   if (keyptr[++y] < 0) return(0);
  456.                   if (keyptr[y + 1] < 0) break;
  457.                 }
  458.           y += 2;
  459.         }
  460.     __setnamefil(nameptr,t.filename);    /* if no ext. add .fil */
  461.     if ((t.fd = open((char *)(t.filename),RWMODE,0)) >= 0)
  462.             { close(t.fd);      ktERRNO = 1;    return(0); }
  463.     if ((t.fd = open(t.filename,CREATMODE)) < 0)
  464.             { ktERRNO = (errno == EMFILE) ? 5 : 10;    return(0); }
  465.     ktERRNO = 0;
  466.     t.inxct = indexcount;
  467.     t.dup = 19284;        /* = 'KT' */
  468.     if (chaining) ++t.dup;
  469.     t.curinx = (k + 3*indexcount)*sizeof(int);
  470.     write(t.fd,(char *)&t,3*sizeof(int));
  471.     t.keys = (int *)malloc(t.curinx);
  472.     if (!t.keys)         { ktERRNO = 7; close(t.fd); return(0);}
  473.     n = t.curinx + 3*sizeof(int);
  474.     z = 3*indexcount;
  475.     for (x = y = 0; x < 3*indexcount; ++x)
  476.         { t.keys[x++] = n;
  477.           n += __inx_size[keyptr[y]]*sizeof(long) + 1 + sizeof(int);
  478.           t.keys[x++] = keyptr[y++];
  479.           t.keys[x] = 0;
  480.           for (;;)
  481.             { if (keyptr[y] < 0) break;
  482.               t.keys[x]++;
  483.               t.keys[z++] = keyptr[y++];
  484.               t.keys[z++] = keyptr[y++];
  485.             }
  486.           ++y;
  487.         }
  488.     y = write(t.fd,(char *)t.keys,t.curinx);
  489.     if (y < 1)
  490.         { close(t.fd);
  491.           free((char *)t.keys);
  492.           return(0);
  493.         }
  494.     memset((char *)__inx,0,99*sizeof(long));
  495.     for (x = 0; x < indexcount; ++x)
  496.         { zz[0] = '0' + x;
  497.           write(t.fd,zz,1);
  498.           q.b = __inx_size[t.keys[3*x + 1]]*sizeof(long);
  499.           write(t.fd,(char *)__inx,q.b);
  500.           q.b += 1 + sizeof(int);
  501.           write(t.fd,q.a,sizeof(int));
  502.         }
  503.     close(t.fd);
  504.     free((char *)t.keys);
  505.     return(1);
  506. }
  507. /************************************************************************
  508. *                                    *
  509. * 2    ktOpen - Open file and read base index                *
  510. *                                    *
  511. ************************************************************************/
  512. void __set_min_size()
  513. {    int x,y,*z,q,a;
  514.     z = &KT->keys[3*KT->inxct];
  515.     KT->minsiz = KT->hks = 1;
  516.     for (x = 0; x < KT->inxct; ++x)
  517.         { y = KT->keys[3*x + 2];
  518.           for (a = 1; a <= y; ++a)
  519.             { q = *z;
  520.               z++;
  521.               q += *z;
  522.               if (*z > KT->hks - 1)          KT->hks = *z + 1;
  523.               if (KT->minsiz < q) KT->minsiz = q;
  524.               z++;
  525.             }
  526.         }
  527. }
  528.  
  529. int ktOpen(char *nameptr,int mode,int indno) /*    mode  : 0 = read only
  530.                             non-0 = read-write
  531.                         indno : which index to open */
  532. {    int x,y;
  533.     _kt_ **t;
  534.  
  535.     if (indno < 0)    { ktERRNO = 4;    return(0); }
  536.     ktERRNO = 0;
  537.     for (y = 0; y < __filect; ++y)    if (!_KT_[y]) break;
  538.     if (y == __filect)
  539.         { _KT_ = (_kt_ **)realloc(_KT_,(++__filect)*sizeof(_kt_ *));
  540.           if (!_KT_)    { ktERRNO = 7;    return(0); }
  541.         }
  542.     KT = _KT_[y] = (_kt_ *)malloc(sizeof(_kt_));
  543.     if (!_KT_[y])    { ktERRNO = 7;    return(0); }
  544.     memset((char *)KT,0,sizeof(_kt_));
  545.     __setnamefil(nameptr,KT->filename);
  546.     if ((KT->fd = open((char *)(KT->filename),RWMODE,0)) < 0)
  547.         ktERRNO = (errno == EMFILE) ? 5 :
  548.              ((errno == EACCES) ? 10 : 2);
  549.     else
  550.      { KT->fsize = lseek(KT->fd,0L,2);
  551.        if (KT->fsize <= 0) ktERRNO = 6;
  552.        else { __seekdata(0L);
  553.           __ktData((char *)KT,3*sizeof(int));
  554.           x = KT->dup - 19284;
  555.           if (x && x != 1 && x != 0x100 && x != 0x101) ktERRNO = 3;
  556.           else { KT->dup = x&1;
  557.              if (KT->dup) KT->dup = 2*sizeof(long);
  558.              if (KT->inxct <= indno) ktERRNO = 4;
  559.              else { KT->keys = (int *)malloc(KT->curinx);
  560.                 if (!KT->keys) ktERRNO = 7;
  561.                 else { if (__ktData((char *)(KT->keys),KT->curinx) > 0)
  562.                     { __next_index(indno);
  563.                       KT->access = mode;
  564.                       KT->start = __inx_size[_INDEXTYPE(KT->inxct-1)]*sizeof(long) +
  565.                       KT->keys[3*KT->inxct - 3] + sizeof(int) + 1;
  566.                       __set_min_size();
  567.                       return(y + 1);
  568.                     }
  569.                     ktERRNO = 8;
  570.                     free((char *)(KT->keys));
  571.                      }
  572.                   }
  573.                }
  574.         }
  575.        close(KT->fd);
  576.      }
  577.     free((char *)KT);
  578.     _KT_[y] = 0;
  579.     return(0);
  580. }
  581. /************************************************************************
  582. *                                    *
  583. * 3    ktChangeIndex - change index                    *
  584. *                                    *
  585. ************************************************************************/
  586.  
  587. int    ktChangeIndex(int fno,int indno)
  588.  
  589. {    if (!__FileOpen(fno)) return(0);
  590.     if (indno < 0 || indno >= KT->inxct) { ktERRNO = 4; return(0); }
  591.     if (indno != KT->curinx)
  592.         { __next_index(indno);
  593.           KT->BaseEntry = KT->inx_entry = 0;
  594.           KT->inx_pos = _FIRSTINDEX;
  595.         }
  596.     return(1);
  597. }
  598. /************************************************************************
  599. *                                    *
  600. * 4    ktFlush - make sure file is written to disk            *
  601. *                                    *
  602. ************************************************************************/
  603. int    ktFlush(int fno)
  604.  
  605. {    union REGS regs;
  606.  
  607.     if (!__FileOpen(fno)) return(0);
  608.     regs.h.ah = 0x45;
  609.     regs.x.bx = KT->fd;
  610.     int86(0x21,®s,®s);
  611.     if (regs.x.cflag)    { close(KT->fd);
  612.                   KT->fd = open(KT->filename,RWMODE,0);
  613.                 }
  614.     else close(regs.x.ax);
  615.     return(1);
  616. }
  617. /************************************************************************
  618. *                                    *
  619. * 5    ktClose - close file                        *
  620. *                                    *
  621. ************************************************************************/
  622.  
  623. int ktClose(int fno)
  624.  
  625. {    if (!__FileOpen(fno)) return(0);
  626.     close(KT->fd);
  627.     free((char *)(KT->keys));
  628.     free((char *)KT);
  629.     _KT_[fno - 1] = NULL;
  630.     return(1);
  631. }
  632. /************************************************************************
  633. *                                    *
  634. * 7    ktAdd - add a record to a file and update indexes        *
  635. *                                    *
  636. ************************************************************************/
  637. void    __add_indexes(char *recpt)
  638. {    int k,y;
  639.  
  640.     k = KT->curinx;
  641.     for (y = 0; y < KT->inxct; ++y)
  642.         if (y != k)    { __next_index(y);
  643.                   __update_index(recpt,0);
  644.                 }
  645.     __next_index(k);
  646.     __update_index(recpt,0);
  647. }
  648.  
  649. int    ktAdd(int fno,void *recpt,int leng)
  650. {    char *areapt;
  651.     int x;
  652.  
  653.     if (leng < 1) ktERRNO = 15;
  654.     else if (__FileOpen(fno))
  655.     { if (__oktowrite())
  656.         { if (leng < KT->minsiz)
  657.             { areapt = (char *)malloc(KT->minsiz);
  658.               memset(areapt,0,KT->minsiz);
  659.               memmove(areapt,(char *)recpt,leng);
  660.               x = (leng > KT->hks) ? leng : KT->hks;
  661.               if (areapt[x-1]) ++x;
  662.             }
  663.           else    { areapt = (char *)recpt;
  664.               x = leng;
  665.             }
  666.           if (__oktoadd(areapt,40))
  667.             { KT->recptr = KT->fsize;
  668.               _PREVCHAIN = _NEXTCHAIN = _STATUS = 0;
  669.               __wrt_elem(areapt,x);
  670.               __add_indexes(areapt);
  671.               if (areapt != (char *)recpt) free(areapt);
  672.               return(1);
  673.             }
  674.           if (areapt != (char *)recpt) free(areapt);
  675.           KT->recptr = 0;
  676.         }
  677.     }
  678.     return(0);
  679. }
  680. /************************************************************************
  681. *                                    *
  682. * 8    ktAddPhys - add a record to file - do not update index        *
  683. *                                    *
  684. ************************************************************************/
  685. int    ktAddPhys(int fno,void *recpt,int leng)
  686.  
  687. {    if (leng <= 0) ktERRNO = 15;
  688.     else    if (__FileOpen(fno))
  689.             if (__oktowrite())
  690.                 { _PREVCHAIN = _NEXTCHAIN = 0;
  691.                   KT->recptr = KT->fsize;
  692.                   _STATUS = 2;
  693.                   __wrt_elem((char *)recpt,leng);
  694.                   return(1);
  695.                 }
  696.     return(0);
  697. }
  698. /************************************************************************
  699. *                                    *
  700. * 9    ktRead - read a record with a specific key            *
  701. *                                    *
  702. ************************************************************************/
  703. int    __nn(char *recpt,int b,int errs)
  704.  
  705. {    int a1,qq;
  706.     long y,z,a2,*inxp;
  707.     inxp = __inx;
  708.     a1 = KT->inx_entry;
  709.     a2 = KT->inx_pos;
  710.     KT->del = 0;
  711.     __read_inx();
  712.     for (;;)
  713.         { if (__FORWARD > 0) { ++KT->inx_entry;
  714.                        qq = (KT->inx_entry >= _INDEXSIZE ||
  715.                         (!b && KT->inx_pos == KT->base &&
  716.                          KT->inx_entry != KT->BaseEntry));
  717.                      }
  718.           else    { --KT->inx_entry;
  719.               qq = (KT->inx_entry <= 0 ||
  720.                    (!b && KT->inx_pos == KT->base &&
  721.                 KT->inx_entry != KT->BaseEntry));
  722.             }
  723.           if (qq)
  724.             { if (KT->inx_pos >= (long)_FIRSTINDEX ||
  725.                 (!b && KT->inx_pos >= KT->base))
  726.                     { ktERRNO = errs;
  727.                       KT->inx_entry = a1;
  728.                       KT->inx_pos = a2;
  729.                       return(0);
  730.                     }
  731.               y = KT->inx_pos;
  732.               KT->inx_pos = *inxp;
  733.               __read_inx();
  734.               for (KT->inx_entry = 1; y != __inx[KT->inx_entry];)
  735.                 ++KT->inx_entry;
  736.               continue;
  737.             }
  738.           if ((z = __inx[KT->inx_entry]) > 0)
  739.                 { KT->recptr = z;
  740.                   return(__read_indexed(recpt));
  741.                 }
  742.           if (z < 0)    { KT->inx_pos = z;
  743.                   __read_inx();
  744.                   KT->inx_entry =
  745.                     (__FORWARD > 0) ? 0 : _INDEXSIZE;
  746.                 }
  747.         }
  748. }
  749.  
  750. int    __Find(int fno,char *recpt)
  751.  
  752. {    int x,y;
  753.     char *temk,*oldk;
  754.  
  755.     if (!__FileOpen(fno)) return(0);
  756.  
  757.     ktERRNO = KT->BaseEntry = 0;
  758.     if (!__setupkey(&temk,NULL))
  759.         { if (ktERRNO == 7) return(0);
  760.           if (!__FORWARD) { ktERRNO = 13;  free(temk);  return(0); }
  761.         }
  762.     if (__lookup(temk))
  763.         { y = __read_indexed(recpt);
  764.           if (!y)    { free(temk);
  765.                   return(0);
  766.                 }
  767.           if (!__setupkey(&oldk,recpt)) { free(temk);
  768.                           return(0);
  769.                         }
  770.           x = __keysmatch(temk,oldk);
  771.           free(oldk);
  772.           if    (!x                ||
  773.             (__FORWARD > 0 && x < 0)    ||
  774.             (__FORWARD < 0 && x > 0))    { free(temk);
  775.                               return(y);
  776.                             }
  777.         }
  778.     if (!__FORWARD)    { ktERRNO = 17;
  779.               y = 0;
  780.             }
  781.     else y = __nn(recpt,1,(__FORWARD > 0) ? 26 : 27);
  782.     free(temk);
  783.     return(y);
  784. }
  785.  
  786. int    ktRead(int fno,void *recpt,...)
  787.  
  788. {    int x;
  789.  
  790.     va_start(__KTap,recpt);
  791.     __FORWARD = 0;
  792.     x = __Find(fno,(char *)recpt);
  793.     va_end(__KTap);
  794.     return(x);
  795. }
  796. /************************************************************************
  797. *                                    *
  798. * 10    ktReadAfter - read record with key >= a specific key,        *
  799. *                                    *
  800. ************************************************************************/
  801.  
  802. int    ktReadAfter(int fno,void *recpt,...)
  803.  
  804. {    int x;
  805.  
  806.     va_start(__KTap,recpt);
  807.     __FORWARD = 1;
  808.     x = __Find(fno,(char *)recpt);
  809.     va_end(__KTap);
  810.     return(x);
  811. }
  812. /************************************************************************
  813. *                                    *
  814. * 11    ktReadBefore - read record with key <= a specific key,        *
  815. *                                    *
  816. ************************************************************************/
  817.  
  818. int    ktReadBefore(int fno,void *recpt,...)
  819.  
  820. {    int x;
  821.  
  822.     va_start(__KTap,recpt);
  823.     __FORWARD = -1;
  824.     x = __Find(fno,(char *)recpt);
  825.     va_end(__KTap);
  826.     return(x);
  827. }
  828. /************************************************************************
  829. *                                    *
  830. * 12    ktLength - check to see if record with a specific key exists    *
  831. *           & return with the record length if it does        *
  832. *           set currency to this record but do not read it    *
  833. *                                    *
  834. ************************************************************************/
  835.  
  836. int    ktLength(int fno,...)
  837.  
  838. {    int x;
  839.     char *temk;
  840.  
  841.     x = __FileOpen(fno);
  842.     if (x)    { va_start(__KTap,fno);
  843.           x = __setupkey(&temk,NULL);
  844.           va_end(__KTap);
  845.           if (ktERRNO == 7) return(0);
  846.           if (!x) ktERRNO = 13;
  847.           else    { KT->BaseEntry = 0;
  848.               x = __Exists(temk);
  849.               if (!x) ktERRNO = 17;
  850.             }
  851.           free(temk);
  852.         }
  853.     return(x);
  854. }
  855. /************************************************************************
  856. *                                    *
  857. * 13    ktNext - read next logical record                 *
  858. *                                    *
  859. ************************************************************************/
  860.  
  861. int    __ktNext(int fno,void *recpt,int s)
  862.  
  863. {    if (!__FileOpen(fno)) return(0);
  864.     if (!s) KT->recptr = 0;
  865.     if (KT->recptr <= 0)    { KT->inx_pos = _FIRSTINDEX;
  866.                   KT->inx_entry = 0;
  867.                 }
  868.     else      if (KT->del == 2) --KT->inx_entry;
  869.     __FORWARD = 1;
  870.     KT->BaseEntry = 0;
  871.     return(__nn((char *)recpt,1,26));
  872. }
  873. int    ktNext(int fno,void *recpt)
  874. {    return(__ktNext(fno,recpt,1));
  875. }
  876. /************************************************************************
  877. *                                    *
  878. * 14    ktPrev - read previous logical record                *
  879. *                                    *
  880. ************************************************************************/
  881.  
  882. int    __ktPrev(int fno,void *recpt,int s)
  883.  
  884. {    if (!__FileOpen(fno)) return(0);
  885.     if (!s) KT->recptr = 0;
  886.     if (KT->recptr <= 0)    { KT->inx_pos = _FIRSTINDEX;
  887.                   KT->inx_entry = _INDEXSIZE;
  888.                 }
  889.     else     if (KT->del == 1) ++KT->inx_entry;
  890.     __FORWARD = KT->BaseEntry = 0;
  891.     return(__nn((char *)recpt,1,27));
  892. }
  893. int    ktPrev(int fno,void *recpt)
  894. {    return(__ktPrev(fno,recpt,1));
  895. }
  896. /************************************************************************
  897. *                                    *
  898. * 15    ktDelete - delete last record read                *
  899. *                                    *
  900. ************************************************************************/
  901. void __delun(char a)
  902. {    long q,r,s,t, r1[2];
  903.     char b;
  904.     s = r = _PREVCHAIN;
  905.     t = r1[1] = q = _NEXTCHAIN;
  906.     if (a == 2) s = t = KT->recptr;
  907.     b = _STATUS;
  908.     __wrtstatus();
  909.     if (KT->dup)
  910.         { if (!r)    { _STATUS = a;
  911.                   for (;r1[1];)
  912.                     { __seekdata(r1[1]);
  913.                       __wrdata((char *)&_STATUS,1);
  914.                       __ktData((char *)&r1[0],2*sizeof(long));
  915.                     }
  916.                   _STATUS = b;
  917.                 }
  918.           else    { __seekdata(r + 1 + sizeof(long));
  919.               __wrdata((char *)&t,sizeof(long));
  920.               if (q)    { __seekdata(++q);
  921.                       __wrdata((char *)&s,sizeof(long));
  922.                     }
  923.             }
  924.         }
  925. }
  926. void    __index_zero(int k)
  927. {    long L,Q;
  928.     int x,y,b;
  929.  
  930.     __inx[KT->inx_entry] = 0;
  931.     if (__inx[0])
  932.         { y = b = Q = 0;
  933.           for (x = 1; x < _INDEXSIZE; ++x)
  934.             if (__inx[x])    { if (++y > 1) break;
  935.                       Q = __inx[x];
  936.                       b = (x < KT->inx_entry) ? 1 : 2;
  937.                     }
  938.           if (y < 2 && Q >= 0)
  939.             { for (;y < 2 && __inx[0];)
  940.                 { L = KT->inx_pos;
  941.                   KT->inx_pos = __inx[0];
  942.                   __read_inx();
  943.                   for (KT->inx_entry = 1;
  944.                        L != __inx[KT->inx_entry];)
  945.                     ++KT->inx_entry;
  946.                   if (KT->BaseEntry && L == KT->base)
  947.                     { KT->base = KT->inx_pos;
  948.                       KT->BaseEntry = KT->inx_entry;
  949.                     }
  950.                   __inx[KT->inx_entry] = Q;
  951.                   y = 0;
  952.                   for (x = 1; x < _INDEXSIZE; ++x)
  953.                     { if (__inx[x]) ++y;
  954.                       if (y > 1) break;
  955.                     }
  956.                 }
  957.               if (k == KT->curinx) KT->del = b;
  958.             }
  959.         }
  960.     __wrt_inx();
  961. }
  962. int    ktDelete(int fno,void *recpt)
  963. {    int x,k;
  964.     char *temk;
  965.     if (__locked(fno))          return(0);
  966.     _STATUS |= '\x80';
  967.     __delun('\x82');
  968.     if (_INDEXED)
  969.         { k = KT->curinx;
  970.           if (KT->inxct > 1)
  971.             { for (x = 0; x < KT->inxct; ++x)
  972.                if (x != k)
  973.                 { __next_index(x);
  974.                   __recordlookup((char *)recpt);
  975.                   __index_zero(x);
  976.                 }
  977.               __next_index(k);
  978.             }
  979.           __recordlookup((char *)recpt);
  980.           __index_zero(k);
  981.         }
  982.     return(1);
  983. }
  984. /************************************************************************
  985. *                                    *
  986. * 16    ktUndelete - undelete last physicalrecord read            *
  987. *                                    *
  988. ************************************************************************/
  989. int    ktUndelete(int fno,void *recpt)
  990.  
  991. {    if (__FileOpen(fno))
  992.     { if (__oktowrite())
  993.         { if (KT->recptr <= 0)  ktERRNO = 20;
  994.           else { if (_DELETED)
  995.             { if (_INDEXED)
  996.                 { if (!__oktoadd((char *)recpt,50)) return(0);
  997.                   __add_indexes((char *)recpt);
  998.                 }
  999.               _STATUS &= '\x7f';
  1000.               __delun(2);
  1001.               return(1);
  1002.             }
  1003.              else ktERRNO = 29;
  1004.            }
  1005.         }
  1006.     }
  1007.     return(0);
  1008. }
  1009. /************************************************************************
  1010. *                                    *
  1011. * 17    ktRewrite - rewrite the last record read            *
  1012. *                                    *
  1013. ************************************************************************/
  1014. union    { int a[2]; char b[4]; } __old_length;
  1015. struct    { long    ix;
  1016.       int    en;} __oldix[10];
  1017.  
  1018. int     __record_moved;
  1019.  
  1020. void    __alter_index(int y,char *recpt)
  1021. {    int x,z;
  1022.     __next_index(y);
  1023.     KT->inx_pos = __oldix[y].ix;
  1024.     KT->inx_entry = __oldix[y].en;
  1025.     if (KT->inx_pos)
  1026.         { __read_inx();
  1027.           if (__alter[y].ix)    { KT->inx_entry = __oldix[y].en;
  1028.                       __index_zero(y);
  1029.                       __update_index(recpt,1);
  1030.                     }
  1031.           else if (__record_moved)
  1032.             { __inx[KT->inx_entry] = KT->recptr;
  1033.               __wrt_inx();
  1034.             }
  1035.         }
  1036. }
  1037. int    ktRewrite(int fno,void *recpt,int length)
  1038.  
  1039. {    int x,y,z,i,j,k,e,f;
  1040.     char *oldk,*keypt,*oldrec,*areapt;
  1041.  
  1042.     long q,r,s,start;
  1043.     if (length < 1)    { ktERRNO = 15;      return(0); }
  1044.     if (__locked(fno)) return(0);
  1045.     if (length < KT->minsiz && _INDEXED)
  1046.         { areapt = (char *)malloc(KT->minsiz);
  1047.           memset(areapt,0,KT->minsiz);
  1048.           memmove(areapt,(char *)recpt,length);
  1049.           if (length < KT->hks) length = KT->hks;
  1050.           if (areapt[length-1]) ++length;
  1051.         }
  1052.     else areapt = (char *)recpt;
  1053.     q = KT->recptr;
  1054.     r = KT->inx_pos;
  1055.     e = KT->inx_entry;
  1056.     k = KT->curinx;
  1057.     start = q + KT->dup + 1;
  1058.     __seekdata(start);
  1059.     __ktData(__old_length.b,2*sizeof(int));
  1060.     __record_moved = (length > __old_length.a[0] + __old_length.a[1]);
  1061.  
  1062.     if (_INDEXED)
  1063.         { __inx_char = q;
  1064.           z = 1;
  1065.           f = (__old_length.a[0] > KT->maxkey) ?
  1066.                __old_length.a[0] : KT->maxkey + 1;
  1067.           oldrec = malloc(f);
  1068.           if (!oldrec) { ktERRNO = 7;
  1069.                  if (areapt != (char *)recpt) free(areapt);
  1070.                  return(0);
  1071.                 }
  1072.           __ktData(oldrec,__old_length.a[0]);
  1073.           for (y = KT->inxct - 1; y >= 0; --y)
  1074.             { __next_index(y);
  1075.               x = 0;
  1076.               if (!__setupkey(&keypt,areapt))
  1077.                 { z = 0; break;}
  1078.               if (!__setupkey(&oldk,oldrec)) { z = 0; break;}
  1079.               __oldix[y].ix = __alter[y].ix = 0;
  1080.               if (__keysmatch(oldk,keypt)) x = __Exists(keypt);
  1081.               if (!x && (__record_moved || __alter[y].ix))
  1082.                 {
  1083.                   KT->inx_pos = _FIRSTINDEX;
  1084.                   for (j = 0; j < _MAXKEY; ++j)
  1085.                     { __read_inx();
  1086.                       i = __inx_key(oldk[j]);
  1087.                       if (!__inx[i]) break;
  1088.                       if ((__inx_char = __inx[i]) > 0)
  1089.                         { KT->recptr = __inx_char;
  1090.                           break;
  1091.                         }
  1092.                       KT->inx_pos = __inx_char;
  1093.                     }
  1094.                   __oldix[KT->curinx].ix = KT->inx_pos;
  1095.                   __oldix[KT->curinx].en = i;
  1096.                 }
  1097.               free(oldk);
  1098.               free(keypt);
  1099.               if (x)    { ktERRNO = 30 + y;
  1100.                       z = 0;
  1101.                       break;
  1102.                     }
  1103.             }
  1104.           __next_index(k);
  1105.           free(oldrec);
  1106.           KT->recptr = q;
  1107.           KT->inx_pos = r;
  1108.           KT->inx_entry = e;
  1109.           if (!z) { if (areapt != (char *)recpt) free(areapt);
  1110.                 return(0);
  1111.               }
  1112.         }
  1113.     if (__record_moved)
  1114.         { KT->recptr = q;
  1115.           _STATUS |= '\x80';
  1116.           __wrtstatus();
  1117.           s = KT->recptr = KT->fsize;
  1118.           _STATUS &= '\x7f';
  1119.           __wrt_elem(areapt,length);
  1120.           if (KT->dup)
  1121.             { if (_PREVCHAIN)
  1122.                 { __seekdata(_PREVCHAIN + 1 + sizeof(long));
  1123.                   __wrdata((char *)&s,sizeof(long));
  1124.                 }
  1125.               if (_NEXTCHAIN)
  1126.                 { __seekdata(_NEXTCHAIN + 1);
  1127.                   __wrdata((char *)&s,sizeof(long));
  1128.                 }
  1129.             }
  1130.         }
  1131.     else    { if (length != __old_length.a[0])
  1132.             { __old_length.a[1] += (__old_length.a[0] - length);
  1133.               __old_length.a[0] = length;
  1134.               __seekdata(start);
  1135.               __wrdata(__old_length.b,2*sizeof(int));
  1136.             }
  1137.           else __seekdata(start + 2*sizeof(int));
  1138.           __wrdata(areapt,length);
  1139.         }
  1140.     if (_INDEXED)    { for (y = 0; y < KT->inxct; ++y)
  1141.                 if (y != k) __alter_index(y,areapt);
  1142.               __alter_index(k,areapt);
  1143.             }
  1144.      if (areapt != (char *)recpt) free(areapt);
  1145.     return(length);
  1146. }
  1147. /************************************************************************
  1148. *                                    *
  1149. * 18    ktGetChar - get character from keyboard             *
  1150. *                                    *
  1151. ************************************************************************/
  1152. char    __runch = 0,__runsc = 0;
  1153.  
  1154. char    ktGetChar()
  1155.  
  1156. {    int d;
  1157.     union REGS regs;
  1158.  
  1159.     if (__runch || __runsc)    { ktCHAR = __runch;
  1160.                   ktSCAN = __runsc;
  1161.                   __runch = __runsc = 0;
  1162.                 }
  1163.     else for (;;)
  1164.          { regs.x.ax = 0;
  1165.            int86(0x16,®s,®s);
  1166.            ktSCAN = regs.h.ah;
  1167.            ktCHAR = regs.h.al;
  1168.            if (ktSCAN < 59 || ktSCAN > 68 || __function) break;
  1169. #ifdef __HELP
  1170.            regs.x.ax = 0x300;
  1171.            regs.x.bx = 0;
  1172.            int86(0x10,®s,®s);
  1173.            d = regs.x.dx;
  1174.            ktFKEY = ktSCAN - 58;
  1175.            __function = 1;
  1176.            __HELP
  1177.            __function = 0;
  1178.            regs.x.dx = d;
  1179.            regs.x.ax = 0x200;
  1180.            regs.x.bx = 0;
  1181.            int86(0x10,®s,®s);
  1182. #else
  1183.            break;
  1184. #endif
  1185.          }
  1186.     return(ktCHAR);
  1187. }
  1188. /************************************************************************
  1189. *                                    *
  1190. * 19    ktGetPress - get character from keyboard             *
  1191. *             but do not remove it from the buffer        *
  1192. *                                    *
  1193. ************************************************************************/
  1194.  
  1195. char    ktGetPress()
  1196.  
  1197. {    __runch = ktGetChar();
  1198.     __runsc = ktSCAN;
  1199.     return(__runch);
  1200. }
  1201. /************************************************************************
  1202. *                                    *
  1203. * 20    ktGetStr - get string from keyboard                 *
  1204. *                                    *
  1205. ************************************************************************/
  1206.  
  1207. int    ktGetStr(char *dataptr,int maxlen)
  1208.  
  1209. {    unsigned char a;
  1210.     int x;
  1211.     if (!maxlen) maxlen = -1;
  1212.     for (x = 0;;)
  1213.         { a = ktGetChar();
  1214.           if (ktSCAN == 1 || a == 13) break;
  1215.           if (ktSCAN == 14)
  1216.             { if (x > 0)    { dataptr[--x] = 0;
  1217.                       __back();
  1218.                     }
  1219.             }
  1220.           else    { if (!a) { if (ktSCAN == 75 && x)
  1221.                     { --x; __ktputch(8); }
  1222.                     else if (ktSCAN == 77 && x < maxlen)
  1223.                     { if (!dataptr[x]) dataptr[x] = ' ';
  1224.                       __ktputch(dataptr[x++]);
  1225.                     }
  1226.                   }
  1227.           else    { if (x >= maxlen) break;
  1228.               if (a > 31)    { dataptr[x++] = a;
  1229.                       __ktputch(a);
  1230.                     }
  1231.             }
  1232.             }
  1233.         }
  1234.     dataptr[x] = 0;
  1235.     return(x);
  1236. }
  1237. /************************************************************************
  1238. *                                    *
  1239. * 21    ktGetKey - get key from keyboard and read record        *
  1240. *                                    *
  1241. ************************************************************************/
  1242. int    __found;
  1243. int    __get_next_part(int k,char *recpt,char *keypt)
  1244. {    int x,y,z,l;
  1245.     char a;
  1246.     long q;
  1247.  
  1248.     y = 1;
  1249.     l = KT->keys[KT->ixdes + 2*k];
  1250.     if (keypt) memset(keypt,0,l);
  1251.     for (x = 0; x < l;)
  1252.         { a = ktGetChar();
  1253.           if (ktSCAN == 14 || (!a && ktSCAN == 75))
  1254.             { if (x) { --x;
  1255.                    if (keypt) keypt[x] = 0;
  1256.                    __back();
  1257.                    if (!x) KT->inx_pos = _FIRSTINDEX;
  1258.                    else    { KT->inx_pos = q;
  1259.                       __read_inx();
  1260.                       q = __inx[0];
  1261.                     }
  1262.                  }
  1263.             }
  1264.           else    { if ESCAPE return(0);
  1265.               if ENTER  a = 0;
  1266.               else { if (a < 32) continue;
  1267.                  __ktputch(a);
  1268.                    }
  1269.               if (keypt) keypt[x] = a;
  1270.               x++;
  1271.               __read_inx();
  1272.               z = __inx_key(a);
  1273.               if ((__inx_char = __inx[z]) > 0)
  1274.                 { KT->recptr = __inx_char;
  1275.                   y = __read_indexed(recpt);
  1276.                   __found = 1;
  1277.                   break;
  1278.                 }
  1279.               if (!__inx_char) return(((a) ? 0 : -1));
  1280.               q = KT->inx_pos;
  1281.               KT->inx_pos = __inx_char;
  1282.               if (!a) return(1);
  1283.             }
  1284.         }
  1285.     return(y);
  1286. }
  1287. int    ktGetKey(int fno,void *recpt,...)
  1288.  
  1289. {    int y,k;
  1290.     char *keypt;
  1291.  
  1292.     y = __FileOpen(fno);
  1293.     va_start(__KTap,recpt);
  1294.     for (k = 0; k < _INDEXPARTS(KT->curinx); ++k)
  1295.         { keypt = va_arg(__KTap,char *);
  1296.           if (!keypt) break;
  1297.           keypt[0] = 0;
  1298.         }
  1299.     va_end(__KTap);
  1300.     if (y)    { keypt = recpt;
  1301.           va_start(__KTap,recpt);
  1302.           KT->inx_pos = _FIRSTINDEX;
  1303.           KT->recptr = KT->BaseEntry = KT->del = 0;
  1304.           for (k = 0; k < _INDEXPARTS(KT->curinx); ++k)
  1305.             { __found = 0;
  1306.               if (keypt) keypt = va_arg(__KTap,char *);
  1307.               y = __get_next_part(k,(char *)recpt,keypt);
  1308.               if (__found || y <= 0) break;
  1309.               __ktseparator();
  1310.             }
  1311.           va_end(__KTap);
  1312.         }
  1313.     return(y);
  1314. }
  1315. /************************************************************************
  1316. *                                    *
  1317. * 22    ktReadAll - get first record whose key matches the mask        *
  1318. *                                    *
  1319. ************************************************************************/
  1320.  
  1321. int    ktReadAll(int fno,void *recpt,...)
  1322.  
  1323. {    int x,y,z;
  1324.     char *tkey,*okey;
  1325.  
  1326.     if (!__FileOpen(fno)) return(0);
  1327.     va_start(__KTap,recpt);
  1328.     x = __setupkey(&tkey,NULL);
  1329.     va_end(__KTap);
  1330.     if (!x && ktERRNO) return(0);
  1331.     KT->BaseEntry = 1;
  1332.     KT->inx_pos = _FIRSTINDEX;
  1333.     KT->base = -1;
  1334.     for (y = _MAXKEY; !tkey[y-1] && y;) --y;
  1335.     for (x = 0; x < y; ++x)
  1336.         { KT->base = KT->inx_pos;
  1337.           __read_inx();
  1338.           z = __inx_key(tkey[x]);
  1339.           if (!__inx[z])    { KT->BaseEntry = 0;
  1340.                       free(tkey);
  1341.                       ktERRNO = 17;
  1342.                       return(0);
  1343.                     }
  1344.           KT->BaseEntry = KT->inx_entry = z;
  1345.           __inx_char = __inx[z];
  1346.           if (__inx_char > 0)
  1347.             { KT->recptr = __inx_char;
  1348.               z = __read_indexed((char *)recpt);
  1349.               if (z) { __setupkey(&okey,(char *)recpt);
  1350.                    for (; x < y ; ++x)
  1351.                     { if (__inx_key(tkey[x]) !=
  1352.                           __inx_key( okey[x]))
  1353.                         { KT->BaseEntry = 0;
  1354.                           z = 0;
  1355.                           ktERRNO = 17;
  1356.                           break;
  1357.                         }
  1358.                     }
  1359.                    free(okey);
  1360.                  }
  1361.               free(tkey);
  1362.               return(z);
  1363.             }
  1364.           KT->inx_pos = __inx_char;
  1365.         }
  1366.     KT->inx_entry = 0;
  1367.     __FORWARD = 1;
  1368.     free(tkey);
  1369.     return(__nn((char *)recpt,0,0));
  1370. }
  1371. /************************************************************************
  1372. *                                    *
  1373. * 23    ktNextAll - get next record whose key matches the mask        *
  1374. *            which was given in the preceding ktReadAll        *
  1375. *                                    *
  1376. ************************************************************************/
  1377. int    __FileBase(void *recpt,int fno)
  1378. {    if (__FileOpen(fno))
  1379.         { if (KT->BaseEntry && KT->base < 0)
  1380.             { if (KT->del && (KT->base > KT->inx_pos ||
  1381.                       KT->inx_entry == KT->BaseEntry))
  1382.                 { if (__FORWARD)
  1383.                     { if (KT->del == 2) --KT->inx_entry;
  1384.                     }
  1385.                   else    { if (KT->del == 1) ++KT->inx_entry;
  1386.                     }
  1387.                 }
  1388.               return(__nn((char *)recpt,0,0));
  1389.             }
  1390.           else ktERRNO = ((KT->BaseEntry) ? 0 : 25);
  1391.         }
  1392.     return(0);
  1393. }
  1394.  
  1395. int    ktNextAll(int fno,void *recpt)
  1396. {    __FORWARD = 1;
  1397.     return(__FileBase(recpt,fno));
  1398. }
  1399. /************************************************************************
  1400. *                                    *
  1401. * 24    ktPrevAll - get previous record whose key matches the mask    *
  1402. *            which was given in the preceding ktReadAll        *
  1403. *                                    *
  1404. ************************************************************************/
  1405.  
  1406. int    ktPrevAll(int fno,void *recpt)
  1407. {    __FORWARD = 0;
  1408.     return(__FileBase(recpt,fno));
  1409. }
  1410. /************************************************************************
  1411. *                                    *
  1412. * 25    ktAddChain - add new record chained to the current record    *
  1413. *                                    *
  1414. ************************************************************************/
  1415.  
  1416. int    ktAddChain(int fno,void *recpt,int leng)
  1417. {    long q,r;
  1418.     if (!__FileReady(fno)) return(0);
  1419.     if (!KT->dup)    { ktERRNO = 23;
  1420.               return(0);
  1421.             }
  1422.     if (!__oktowrite()) return(0);
  1423.     if (leng < 1)    { ktERRNO = 15;    return(0); }
  1424.     q = KT->fsize;
  1425.     __seekdata(KT->recptr + 1 + sizeof(long));
  1426.     __wrdata((char *)&q,sizeof(long));
  1427.     r = _NEXTCHAIN;
  1428.     if (r)    { __seekdata(++r);
  1429.           __wrdata((char *)&q,sizeof(long));
  1430.         }
  1431.     _PREVCHAIN = KT->recptr;
  1432.     KT->recptr = q;
  1433.     _STATUS = 2;
  1434.     __wrt_elem((char *)recpt,leng);
  1435.     return(1);
  1436. }
  1437. /************************************************************************
  1438. *                                    *
  1439. * 26    ktNextChain - read next record chained to the current record    *
  1440. *                                    *
  1441. ************************************************************************/
  1442. int    __NChain(void *recpt,int fno,int n)
  1443. {    long q;
  1444.     if (__FileOpen(fno))
  1445.     { if (!KT->dup)                ktERRNO = 23;
  1446.       else { if (KT->recptr <= 0)        ktERRNO = 20;
  1447.       else { if (_DELETED && !KT->chain[0]) ktERRNO = 28;
  1448.       else { q = KT->chain[n];
  1449.          if (q)    { KT->recptr = q;
  1450.               __seekdata(q);
  1451.               __ktData((char *)&_STATUS,1);
  1452.               return(__read_elem((char *)recpt));
  1453.             }
  1454.            }
  1455.            }
  1456.            }
  1457.     }
  1458.     return(0);
  1459. }
  1460.  
  1461. int    ktNextChain(int fno,void *recpt)
  1462. {    return(__NChain(recpt,fno,1));
  1463. }
  1464. /************************************************************************
  1465. *                                    *
  1466. * 27    ktPrevChain - read previous record chained to the current record*
  1467. *                                    *
  1468. ************************************************************************/
  1469.  
  1470. int    ktPrevChain(int fno,void *recpt)
  1471. {    return(__NChain(recpt,fno,0));
  1472. }
  1473. /************************************************************************
  1474. *                                    *
  1475. * 28    ktStart - read first logical record in the file            *
  1476. *                                    *
  1477. ************************************************************************/
  1478.  
  1479. int    ktStart(int fno,void *recpt)
  1480. {    return(__ktNext(fno,recpt,0));
  1481. }
  1482. /************************************************************************
  1483. *                                    *
  1484. * 29    ktEnd - read last logical record in the file            *
  1485. *                                    *
  1486. ************************************************************************/
  1487.  
  1488. int    ktEnd(int fno,void *recpt)
  1489. {    return(__ktPrev(fno,recpt,0));
  1490. }
  1491. /************************************************************************
  1492. *                                    *
  1493. * 30    ktNextPhys - read next physical record                *
  1494. *                                    *
  1495. ************************************************************************/
  1496.  
  1497. int     __record_status()
  1498. {    __seekdata(KT->recptr);
  1499.     __ktData((char *)&_STATUS,1);
  1500.     ktINDEXED = _INDEXED;
  1501.     return (_STATUS < '0' || _STATUS > '9');
  1502. }
  1503. int    __ktNextPhys(int fno,void *recpt,int s)
  1504.  
  1505. {    int y;
  1506.     if (!__FileOpen(fno)) return(0);
  1507.     if (!s) KT->recptr = 0;
  1508.     KT->recptr = (KT->recptr <= 0) ? KT->start : KT->nexrec;
  1509.     for (;;)
  1510.         { if (KT->recptr >= KT->fsize)
  1511.             { ktERRNO = 19;    return(0); }
  1512.           if (__record_status()) break;
  1513.           KT->recptr += 1 + sizeof(int) +
  1514.             __inx_size[_INDEXTYPE(_STATUS-'0')]*sizeof(long);
  1515.         }
  1516.     y = __read_elem((char *)recpt);
  1517.     return( ((_DELETED) ? -y : y));
  1518. }
  1519. int    ktNextPhys(int fno,void *recpt)
  1520. {    return(__ktNextPhys(fno,recpt,1));
  1521. }
  1522. /************************************************************************
  1523. *                                    *
  1524. * 31    ktPrevPhys - read previous physical record            *
  1525. *                                    *
  1526. ************************************************************************/
  1527. int    __PrevPhys(char *recpt,int fno,int s)
  1528. {    int  z;
  1529.  
  1530.     if (!__FileOpen(fno)) return(0);
  1531.     if (!s) KT->recptr = 0;
  1532.     if (KT->recptr <= 0)    KT->recptr = KT->fsize;
  1533.     for (;;)
  1534.         { if (KT->recptr <= KT->start)    { ktERRNO = 21; return(0); }
  1535.           __seekdata(KT->recptr - (long)sizeof(int));
  1536.           __ktData((char *)&z,sizeof(int));
  1537.           KT->recptr -= z;
  1538.           if (__record_status()) break;
  1539.         }
  1540.     z = __read_elem((char *)recpt);
  1541.     return( ((_DELETED) ? -z : z));
  1542. }
  1543.  
  1544. int    ktPrevPhys(int fno,void *recpt)
  1545.  
  1546. {    return(__PrevPhys((char *)recpt,fno,1));
  1547. }
  1548. /************************************************************************
  1549. *                                    *
  1550. * 32    ktStartPhys - read first physical record in the file        *
  1551. *                                    *
  1552. ************************************************************************/
  1553.  
  1554. int    ktStartPhys(int fno,void *recpt)
  1555. {    return(__ktNextPhys(fno,recpt,0));
  1556. }
  1557. /************************************************************************
  1558. *                                    *
  1559. * 33    ktEndPhys - read last physical record in the file        *
  1560. *                                    *
  1561. ************************************************************************/
  1562.  
  1563. int    ktEndPhys(int fno,void *recpt)
  1564. {    return(__PrevPhys((char *)recpt,fno,0));
  1565. }
  1566. /************************************************************************
  1567. *                                    *
  1568. * 34    ktLock - lock last  record read                    *
  1569. *                                    *
  1570. ************************************************************************/
  1571. char    __FirstChar(int y,int fno)
  1572. {    if (!__FileReady(fno)) return(0);
  1573.     _STATUS = (_STATUS&254)|y;
  1574.     __wrtstatus();
  1575.     ktFlush(fno);
  1576.     return(1);
  1577. }
  1578.  
  1579. int    ktLock(int fno)
  1580. {    return(__FirstChar(1,fno));
  1581. }
  1582. /************************************************************************
  1583. *                                    *
  1584. * 35    ktUnlock - unlock last  record read                *
  1585. *                                    *
  1586. ************************************************************************/
  1587.  
  1588. int    ktUnlock(int fno)
  1589. {    return(__FirstChar(0,fno));
  1590. }
  1591. /************************************************************************
  1592. *                                    *
  1593. * 36    ktLocked - returns true if record exists and is locked        *
  1594. *                                    *
  1595. ************************************************************************/
  1596.  
  1597. int    ktLocked(int fno,...)
  1598. {    char x[2],*temk;
  1599.     int k;
  1600.  
  1601.     if (__FileOpen(fno))    { va_start(__KTap,fno);
  1602.                   k = __setupkey(&temk,NULL);
  1603.                   va_end(__KTap);
  1604.                   if (!k) ktERRNO = 13;
  1605.                   else    { k = __Exists(temk);
  1606.                       if (!k) ktERRNO = 17;
  1607.                       else k = _LOCKED;
  1608.                     }
  1609.                   free(temk);
  1610.                 }
  1611.     return(k);
  1612. }
  1613. /************************************************************************
  1614. *                                    *
  1615. * 37    ktSize - returns the size of the file in bytes            *
  1616. *                                    *
  1617. ************************************************************************/
  1618.  
  1619. long    ktSize(int fno)
  1620. {    if (!__FileOpen(fno)) return(0L);
  1621.     return(KT->fsize);
  1622. }
  1623. /************************************************************************
  1624. *                                    *
  1625. * 38    ktRecords - returns the size of the file in records        *
  1626. *                                    *
  1627. ************************************************************************/
  1628.  
  1629. long    ktRecords(int fno,int typ)
  1630. {    long x,l;
  1631.     char a[8],b,c;
  1632.     if (!__FileOpen(fno)) return(0L);
  1633.  
  1634.     l = KT->start;
  1635.     for (x = 0;l < KT->fsize;)
  1636.         { __seekdata(l);
  1637.           __ktData(a,1);
  1638.           if (a[0] >= '0' && a[0] <= '9')
  1639.             l += __inx_size[_INDEXTYPE(a[0] - '0')]*sizeof(long)
  1640.               + 1 + sizeof(int);
  1641.           else    { b = a[0] & 0x80;
  1642.               if (!typ || (typ > 0 && !b) || (typ < 0 && b))
  1643.                  ++x;
  1644.               if (KT->dup) __ktData(a,KT->dup);
  1645.               __ktData(__tmplen.b,2*sizeof(int));
  1646.               l += 1 + KT->dup + 3*sizeof(int) +
  1647.                    __tmplen.a[0] + __tmplen.a[1];
  1648.             }
  1649.         }
  1650.     return(x);
  1651. }
  1652. /************************************************************************
  1653. *                                    *
  1654. * 39    ktMaxRead - sets the maximum number of bytes for any read    *
  1655. *                                    *
  1656. ************************************************************************/
  1657.  
  1658. int    ktMaxRead(int fno,int max)
  1659. {    if (__FileOpen(fno))    { if (max < 0 || (max > 0 && max < KT->minsiz))
  1660.                       ktERRNO = 15;
  1661.                   else    { KT->maxread = max;
  1662.                       return(KT->minsiz);
  1663.                     }
  1664.                 }
  1665.         return(0);
  1666. }
  1667.