home *** CD-ROM | disk | FTP | other *** search
/ Jason Aller Floppy Collection / 125.img / PRO-C4.ZIP / BENCH1.ZIP / BENCH / ICODEBSE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-28  |  31.6 KB  |  1,125 lines

  1. /* ==( io/src/icodebse.c )== */
  2.  
  3. /* ----------------------------------------------- */
  4. /* Pro-C  Copyright (C) 1988 - 1990 Vestronix Inc. */
  5. /* Modification to this source is not supported    */
  6. /* by Vestronix Inc.                               */
  7. /*            All Rights Reserved                  */
  8. /* ----------------------------------------------- */
  9. /* Written   NA   24-Feb-88                        */
  10. /* Modified  VV   12-Apr-90  See comments below    */
  11. /* ----------------------------------------------- */
  12. /* %W%  (%H% %T%) */
  13.  
  14. /*
  15.  *  Modifications
  16.  *
  17.  *  12-Apr-90  VvA - correction to next/prev fns at EOF/TOF
  18.  *  28-Mar-90  VvA - adjustments for locking modes, transactions
  19.  *  12-Feb-90  VvA - adjustment to PACK request
  20.  *  01-Feb-90  VvA - fld_cnt now in iogen.c, fd[] struct
  21.  *  01-Feb-90  VvA - Enabled openmode in open_file()
  22.  *  26-Jan-90  VvA - CLIPPER support thru assign_IO_CL
  23.  *  15-Dec-89  VvA - V.2 modifications
  24.  *  01-Sep-89  VvA - Added date, memo, logical dBASE fields
  25.  *  01-Sep-89  VvA - Modified for generic I/O interface
  26.  *  01-Apr-89  VvA - Adapted for CodeBase4 from dBC III+
  27.  *  01-Sep-88  VvA - Adapted for dBASE/dBC III+
  28. */
  29.  
  30. /*  CodeBase 4 I/O calls via general IOGEN.C interface  */
  31.  
  32.  
  33. # include <stdio.h>
  34. # include <d4base.h>
  35. # include <iodef.h>
  36. # include <iomsg.h>
  37. # include <proc.io>
  38. # include <bench.h>
  39. # include <iosup.h>
  40.  
  41.  
  42. #define       TIMEOUTMAX      500         /* lock attempts before giving up */
  43. #define       CBERROR         -1                  /* signals CodeBase error */
  44. #define       DBFINACT        '*'                    /* dBASE deletion flag */
  45. #define       DBFNULL        (BASE *)0    /* null database ptr for CodeBase */
  46.  
  47.  
  48. /* Function prototypes */
  49. # ifdef ANSI
  50. static int i_addrec(int, char *);
  51. static int i_close_file(int, char *);
  52. static int i_commit(int, char *);
  53. static int i_delrec(int, char *);
  54. static int i_filename(int, char *);
  55. static int i_findkey(int, char *);
  56. static int i_firstkey(int, char *);
  57. static int i_init_file(int, char *);
  58. static int i_lastkey(int, char *);
  59. static int i_lockrec(int, char *);
  60. static int i_login(int, char *);
  61. static int i_logoff(int, char *);
  62. static int i_nextrec(int, char *);
  63. static int i_open_file(int, char *);
  64. static int i_prevrec(int, char *);
  65. static int i_rereadrec(int, char *);
  66. static int i_rollback(int, char *);
  67. static int i_selectinx(int, char *);
  68. static int i_transact(int, char *);
  69. static int i_unlock_rec(int, char *);
  70. static int i_updrec(int, char *);
  71. static int create_file(int, char *, int);
  72. static int load_keys(int, int);
  73. static int create_index(int, int, char *);
  74. static int length_check(int);
  75. static int setupkey(int, char *, char *);
  76. static int get_record(int, char *, int);
  77. static int put_record(int, char *);
  78. static int io_xlate(int, int, char *);
  79. # else
  80. static int i_addrec();
  81. static int i_close_file();
  82. static int i_commit();
  83. static int i_delrec();
  84. static int i_filename();
  85. static int i_findkey();
  86. static int i_firstkey();
  87. static int i_init_file();
  88. static int i_lastkey();
  89. static int i_lockrec();
  90. static int i_login();
  91. static int i_logoff();
  92. static int i_nextrec();
  93. static int i_open_file();
  94. static int i_prevrec();
  95. static int i_rereadrec();
  96. static int i_rollback();
  97. static int i_selectinx();
  98. static int i_transact();
  99. static int i_unlock_rec();
  100. static int i_updrec();
  101. static int create_file();
  102. static int load_keys();
  103. static int create_index();
  104. static int length_check();
  105. static int setupkey();
  106. static int get_record();
  107. static int put_record();
  108. static int io_xlate();
  109. # endif
  110.  
  111.  
  112. extern int v4error;                                  /* CodeBase error code */
  113.  
  114. #ifdef TC
  115. extern unsigned _stklen = 10000;          /* default stack size for Turbo C */
  116. #endif
  117.  
  118.  
  119. /*
  120.  * structure for CodeBase-specific values 
  121. */
  122. struct dbf_def
  123. {
  124.    long recnum;                    /* current CodeBase record for this file */
  125.    int dbrec_len;                     /* record length of dBASE type record */
  126.    long fld_ref[MAX_FLDS];
  127.    int ndx_num[MAX_KEYS];
  128. };
  129.  
  130.  
  131. static struct dbf_def fdbf[MAX_FILES];
  132. static int enable_clipper;
  133.  
  134.  
  135. /*
  136.  *
  137.  * Interface Functions
  138.  *
  139. */
  140.  
  141.  
  142. /*
  143.  *  Sets up File Name extension.
  144. */
  145. static int i_filename(fd_sys, buffer)
  146. int fd_sys;
  147. char *buffer;
  148. {
  149.    for ( ; (*buffer != '.') && (*buffer != NULL); buffer++)
  150.       ;
  151.    *buffer = NULL;
  152.  
  153.    return(IOGOOD);
  154. }
  155.  
  156. /*
  157.  *  File initialization
  158. */
  159. static int i_init_file(fd_sys, buffer)
  160. int fd_sys;
  161. char *buffer;
  162. {
  163.    return(IOGOOD);
  164. }
  165.  
  166. /*
  167.  *  File open function
  168. */
  169. static int i_open_file(fd_sys, buffer)
  170. int fd_sys;
  171. char *buffer;
  172. {
  173.    int stat;
  174.    char dbfname[FILENAME_LEN];
  175.    struct fd_def *fptr = &fd[fd_sys];
  176.    struct dbf_def *dptr = &fdbf[fd_sys];
  177.  
  178.    strcpy(dbfname, fptr->filname);
  179.    strcat(dbfname, ".DBF");         /* dBASE III type filename from filname */
  180.  
  181.    if (fptr->openmode & OUTPUT_FLAG)
  182.       create_file(fd_sys, dbfname, 0);  /* if OUTPUT, delete existing files */
  183.  
  184.    if (access(dbfname, 0) == IOGOOD)               /* if the file exists... */
  185.    {
  186.       if ((stat = d4use(dbfname)) == CBERROR)
  187.          return(io_xlate(fd_sys, v4error, "CB4 OPEN1"));
  188.  
  189.       fptr->fd_num = stat;                  /* file has opened successfully */
  190.    }
  191.    else if (!(fptr->openmode & INPUT_FLAG))
  192.    {
  193.       if (create_file(fd_sys, dbfname, 1) != IOGOOD)
  194.          return(IOERROR);
  195.    }
  196.    else
  197.       return(io_xlate(fd_sys, v4error, "CB4 OPEN2"));
  198.  
  199.    if (length_check(fd_sys) != IOGOOD)
  200.    {
  201.       i_close_file(fd_sys, buffer);
  202.       return(IOERROR);
  203.    }
  204.  
  205.    return(IOGOOD);
  206. }
  207.  
  208. /*
  209.  *  CodeBase create file function
  210.  *  - file will be opened by the create call, stat is the file descriptor
  211. */
  212. static int create_file(fd_sys, dfname, saf)
  213. int fd_sys;                                          /* index into fd table */
  214. char *dfname;
  215. int saf;                           /* 0 to destroy old file, 1 to retain it */
  216. {
  217.    int stat, j, foffset = 1;
  218.    FIELD *fldtmp;
  219.    struct fd_def *fptr = &fd[fd_sys];
  220.    struct dbf_def *dptr = &fdbf[fd_sys];
  221.  
  222.    fldtmp = (FIELD *)alloc(sizeof(FIELD) * fptr->fld_cnt);
  223.  
  224.    for (j = 0; j < fptr->fld_cnt; j++)           /* load field descriptions */
  225.    {
  226.       strcpy(fldtmp[j].name, cvt_upper(fptr->flds[j].fldname));
  227.       fldtmp[j].offset = foffset;
  228.       fldtmp[j].decimals = (char)0;
  229.       switch(fptr->flds[j].fldtype)
  230.       {
  231.          case CHRTYP :
  232.             fldtmp[j].type  = (int)'C';
  233.             fldtmp[j].width = (char)fptr->flds[j].fldlen;
  234.             break;
  235.          case INTTYP :
  236.          case LNGTYP :
  237.          case FLTTYP :
  238.          case DBLTYP :
  239.             fldtmp[j].type  = (int)'N';
  240.             fldtmp[j].width = (char)nummasklen(fptr->flds[j].fldmask);
  241.             fldtmp[j].decimals = (char)decmasklen(fptr->flds[j].fldmask);
  242.             break;
  243.          case DATTYP :
  244.                 if (fptr->flds[j].fldlen == 6)
  245.                 {
  246.                     fldtmp[j].type  = (int)'D';
  247.                      fldtmp[j].width = (char)8;
  248.                 }
  249.                 else
  250.                 {
  251.                     fldtmp[j].type = (int)'N';
  252.                     fldtmp[j].width = (char)10;
  253.                     fldtmp[j].decimals = (char)0;
  254.                 }
  255.                  break;
  256.          case LOGTYP :
  257.             fldtmp[j].type = (int)'L';
  258.             fldtmp[j].width = (char)1;
  259.             break;
  260.          case MEMTYP :
  261.             fldtmp[j].type = (int)'M';
  262.             fldtmp[j].width = (char)10;
  263.             break;
  264.       }      
  265.       foffset += fldtmp[j].width;
  266.    }
  267.  
  268.    if ((stat = d4create(dfname, fptr->fld_cnt, fldtmp, saf)) == CBERROR)
  269.    {
  270.       free(fldtmp);
  271.       return(io_xlate(fd_sys, v4error, "CB4 CRT1"));
  272.    }
  273.    free(fldtmp);
  274.  
  275.    fptr->fd_num = stat;                  /* created file is also opened now */
  276.  
  277.    return((load_keys(fd_sys, TRUE) > 0) ? IOGOOD : IOERROR);
  278. }
  279.  
  280. /*
  281.  *  Key load function - creates or opens indexes for new files 
  282.  *  - if creatndx is TRUE, index will be created, otherwise it is opened
  283. */
  284. static int load_keys(fd_sys, creatndx)
  285. int fd_sys, creatndx;
  286. {
  287.    int stat, ndxid, n;
  288.    char ndxname[FILENAME_LEN];
  289.    struct fd_def *fptr = &fd[fd_sys];
  290.  
  291.    strcpy(ndxname, fptr->filname);    /* index names match their file names */
  292.    if ((ndxid = strlen(ndxname)) > 7)           /* ndxid is index id offset */
  293.       ndxid = 7;
  294.    ndxname[ndxid] = '\0';
  295.  
  296.    if (enable_clipper)             /* if assign_IO_CL() called from applicn */
  297.       strcat(ndxname, "0.NTX");
  298.    else
  299.       strcat(ndxname, "0.NDX");
  300.  
  301.    n = 0;
  302.    while (fptr->keys[n].segcount != -1)
  303.    {
  304.       ndxname[ndxid] = (char)(n + 49);      /* sequential index name suffix */
  305.  
  306.       if (creatndx)                                   /* create the indexes */
  307.       {
  308.          if ((stat = create_index(fd_sys, n, ndxname)) < 0)
  309.             return(stat);           /* if negative return, no index created */
  310.       }
  311.       else if ((stat = i4open(ndxname)) == CBERROR)         /* open indexes */
  312.          return(io_xlate(fd_sys, v4error, "CB4 IXOPEN"));    /* returns neg */
  313.  
  314.       fdbf[fd_sys].ndx_num[n] = stat;
  315.       n++;                                        /* & increment key number */
  316.    }
  317.  
  318.    return(n);                       /* value returned is the number of keys */
  319. }
  320.  
  321. /*
  322.  *  Index create function
  323. */
  324. static int create_index(fd_sys, n, ndxname)
  325. int fd_sys, n;
  326. char *ndxname;
  327. {
  328.    int stat, m, fx;
  329.    char keyname[FLDNAME_LEN * MAX_SEGS * 3], fmtstr[12];
  330.    struct fd_def *fptr = &fd[fd_sys];
  331.  
  332.    keyname[0] = '\0';
  333.    for (m = 0; m < fptr->keys[n].segcount; m++)
  334.    {
  335.       fx = fptr->keys[n].fldindex[m];
  336.  
  337.       if (m > 0)
  338.          strcat(keyname, "+");
  339.       if (fptr->keys[n].segcount == 1)      /* no conversion for simple key */
  340.          strcat(keyname, cvt_upper(fptr->flds[fx].fldname));
  341.       else
  342.       {                           /* for compound key all types are strings */
  343.          switch(fptr->flds[fx].fldtype)
  344.          {
  345.             case CHRTYP :
  346.                if (fptr->flds[fx].fldlen == fptr->keys[n].seglen[m])
  347.                   strcat(keyname, cvt_upper(fptr->flds[fx].fldname));
  348.                else
  349.                {
  350.                   strcat(keyname, "SUBSTR(");
  351.                   strcat(keyname, cvt_upper(fptr->flds[fx].fldname));
  352.                   zerorec(fmtstr, 12);
  353.                   sprintf(fmtstr, ",%d,%d)", 
  354.                      (fptr->keys[n].segstart[m]+1 - fptr->flds[fx].fldstart), 
  355.                      fptr->keys[n].seglen[m]);
  356.                   strcat(keyname, fmtstr);
  357.                }
  358.                break;
  359.             case DATTYP :
  360.                     if (fptr->flds[fx].fldlen == 6)
  361.                     {
  362.                    strcat(keyname, "DTOC(");
  363.                    strcat(keyname, cvt_upper(fptr->flds[fx].fldname));
  364.                    strcat(keyname, ")");
  365.                     }
  366.                     else                /* long int dates treated like numbers */
  367.                     {
  368.                       strcat(keyname, "STR(");
  369.                    strcat(keyname, cvt_upper(fptr->flds[fx].fldname));
  370.                    strcat(keyname, ",10,0)");
  371.                     }
  372.                break;
  373.             case INTTYP :
  374.             case LNGTYP :
  375.             case FLTTYP :
  376.             case DBLTYP :
  377.                zerorec(fmtstr, 12);
  378.                sprintf(fmtstr, ",%d,%d)", nummasklen(fptr->flds[fx].fldmask), decmasklen(fptr->flds[fx].fldmask));
  379.                strcat(keyname, "STR(");
  380.                strcat(keyname, cvt_upper(fptr->flds[fx].fldname));
  381.                strcat(keyname, fmtstr);
  382.                break;
  383.          }
  384.       }
  385.    }
  386.  
  387.    if ((stat = i4index(ndxname, keyname, 0, 0)) == CBERROR)
  388.       return(io_xlate(fd_sys, v4error, "CB4 IXCRTE"));     /* retn negative */
  389.    return(stat);
  390. }
  391.  
  392. /*
  393.  *  Length check - checks record length against that expected by PRO-C
  394. */
  395. static int length_check(fd_sys)
  396. int fd_sys;
  397. {
  398.    int i;
  399.    struct fd_def *fptr = &fd[fd_sys];
  400.    struct dbf_def *dptr = &fdbf[fd_sys];
  401.    BASE *infoptr;
  402.  
  403.    dptr->dbrec_len = 1;            /* starts off allowing for deletion byte */
  404.  
  405.    for (i = 0; i < fptr->fld_cnt; i++)               /* record length check */
  406.    {
  407.       switch (fptr->flds[i].fldtype)
  408.       {
  409.          case DATTYP :
  410.                 if (fptr->flds[i].fldlen == 6)
  411.                 dptr->dbrec_len += 8;           /* dBASE format date storage */
  412.                 else
  413.                     dptr->dbrec_len += 10;           /* PRO-C long int date type */
  414.             break;
  415.          case CHRTYP :
  416.             dptr->dbrec_len += fptr->flds[i].fldlen;
  417.             break;
  418.          case INTTYP :
  419.          case LNGTYP :
  420.          case FLTTYP :
  421.          case DBLTYP :
  422.             dptr->dbrec_len += nummasklen(fptr->flds[i].fldmask);
  423.             break;
  424.          case LOGTYP :
  425.             dptr->dbrec_len += 1;
  426.             break;
  427.          case MEMTYP :
  428.             dptr->dbrec_len += 10;
  429.             break;
  430.       }
  431.    }             /* dbrec_len is PRO-C field length adjusted to .DBF format */
  432.  
  433.    if ((infoptr = d4ptr()) == DBFNULL)
  434.       return(io_xlate(fd_sys, v4error, "CB4 LCHK"));
  435.  
  436.    if (dptr->dbrec_len != infoptr->buffer_len)
  437.    {                                  /* if file length has been changed... */
  438.       errmsg(FileRecLenChg_s, fptr->filname);
  439.       return(IOERROR);
  440.    }
  441.  
  442.    for (i = 0; i < fptr->fld_cnt; i++)          /* assign field ref numbers */
  443.    {
  444.       dptr->fld_ref[i] = f4j_ref(i+1);
  445.       if (dptr->fld_ref[i] == (long)CBERROR)
  446.       {
  447.          errmsg(FileFldRef_s, cvt_upper(fptr->flds[i].fldname));
  448.          return(IOERROR);
  449.       }
  450.    }
  451.  
  452.    return((load_keys(fd_sys, FALSE) > 0) ? IOGOOD : IOERROR);
  453. }
  454.  
  455. /*
  456.  *  File close function
  457. */
  458. static int i_close_file(fd_sys, buffer)
  459. int fd_sys;
  460. char *buffer;
  461. {
  462.    if (d4close() == CBERROR)
  463.       return(io_xlate(fd_sys, v4error, "CB4 CLOSE"));
  464.  
  465.    fd[fd_sys].active = NO;
  466.    return(IOGOOD);
  467. }
  468.  
  469.  
  470. /*
  471.  *  Select an index to perform processing on
  472.  *  - uses calls analogous to dBASE "SELECT <dbf file alias>" and 
  473.  *    "SET INDEX TO <ndx file>"
  474. */
  475. static int i_selectinx(fd_sys, buffer)
  476. int fd_sys;
  477. char *buffer;
  478. {
  479.    if (d4select(fd[fd_sys].fd_num) == CBERROR)
  480.       return(io_xlate(fd_sys, v4error, "CB4 SELIX1"));
  481.  
  482.    if (i4select(fdbf[fd_sys].ndx_num[fd[fd_sys].cur_key]) == CBERROR)
  483.       return(io_xlate(fd_sys, v4error, "CB4 SELIX2"));
  484.  
  485.    return(IOGOOD);
  486. }
  487.  
  488. /*
  489.  *  Find a record by key value
  490. */
  491. static int i_findkey(fd_sys, buffer)
  492. int fd_sys;
  493. char *buffer;
  494. {
  495.    int errcode, len, fx;
  496.    double dtmp;
  497.    char keybuff[MAX_FLDLEN * MAX_SEGS + MAX_SEGS];
  498.    struct fd_def *fptr = &fd[fd_sys];
  499.    struct keyinfo *kptr = &fd[fd_sys].keys[fd[fd_sys].cur_key];
  500.  
  501.    i_selectinx(fd_sys, buffer);   /* ensure required file & index selected */
  502.    len = setupkey(fd_sys, buffer, keybuff);
  503.    fx = kptr->fldindex[0];
  504.  
  505.    if ((fptr->flds[fx].fldtype == CHRTYP)
  506.         || ((fptr->flds[fx].fldtype == DATTYP) && (fptr->flds[fx].fldlen == 6))
  507.         || (kptr->segcount > 1))
  508.       errcode = d4seek(keybuff);
  509.    else                                      /* non-compound numerical keys */
  510.    {
  511.       dtmp = c4atod(keybuff, len);
  512.       errcode = d4seek((char *) &dtmp);
  513.    }
  514.  
  515.    if (errcode == -1)
  516.       return(io_xlate(fd_sys, v4error, "CB4 FIND"));
  517.    else if (errcode != 0)                          /* exact value not found */
  518.       if ((fptr->exact && (errcode > 0)) || (errcode == 3))
  519.          return(IONOKEY);
  520.                                    /* otherwise partial match has succeeded */
  521.  
  522.    errcode = get_record(fd_sys, buffer, NEXT);
  523.    return((fptr->exact && (errcode == IOEOF)) ? IONOKEY : errcode);
  524. }
  525.  
  526. /*
  527.  *  Set up target key 
  528.  *  - sets up a key string for record retrieval on current index
  529.  *  - simple keys will use native type in key searches, compound keys are
  530.  *    treated as though all fields converted to string type
  531. */
  532. static int setupkey(fd_sys, recbuf, keybuf)
  533. int fd_sys;
  534. char *recbuf, *keybuf;
  535. {
  536.    int i, j, ofs, len, fx, so = 0, nnum, ndec;
  537.    int itmp;
  538.    long ltmp;
  539.    float ftmp;
  540.    double dtmp;
  541.    char *tptr, stmp[20];
  542.    struct fd_def *fptr = &fd[fd_sys];
  543.    struct dbf_def *dptr = &fdbf[fd_sys];
  544.    struct keyinfo *kptr = &fd[fd_sys].keys[fd[fd_sys].cur_key];
  545.  
  546.    memset(keybuf, (int)' ', MAX_FLDLEN * MAX_SEGS);
  547.  
  548.    for (i = 0; i < kptr->segcount; i++)
  549.    {
  550.       ofs = kptr->segstart[i];
  551.       len = kptr->seglen[i];
  552.       fx = kptr->fldindex[i];
  553.  
  554.       switch(fptr->flds[fx].fldtype)              /* data type of key field */
  555.       {
  556.          case DATTYP :
  557.                 if (len == 6)             /* date seen by PRO-C as ASCII string */
  558.             {
  559.                 strncpy(&keybuf[so], "19", 2);
  560.                if (!recbuf[ofs])
  561.                   strcpy(stmp, "000101");
  562.                else
  563.                   strncpy(stmp, &recbuf[ofs], len);
  564.                 strncpy(&keybuf[so+2], stmp, 6);
  565.                 so += 8;
  566.                 break;
  567.                 }                 /* for long int date type fall thru to LNGTYP */
  568.          case LNGTYP :                               /* don't move this !!! */
  569.             bytecpy(<mp, &recbuf[ofs], len); 
  570.             dtmp = (double)ltmp;
  571.             break;
  572.          case CHRTYP :
  573.             strncpy(&keybuf[so], &recbuf[ofs], len);
  574.             for (j = strlen(&recbuf[ofs]); j < len; j++)
  575.                keybuf[so+j] = ' ';                       /* pad with spaces */
  576.             so += len;
  577.             break;
  578.          case INTTYP :
  579.             bytecpy(&itmp, &recbuf[ofs], len);
  580.             dtmp = (double)itmp;
  581.             break;
  582.          case FLTTYP :
  583.             bytecpy(&ftmp, &recbuf[ofs], len); 
  584.             dtmp = (double)ftmp;
  585.             break;
  586.          case DBLTYP :
  587.             bytecpy(&dtmp, &recbuf[ofs], len); 
  588.             break;
  589.       }
  590.  
  591.       if ((fptr->flds[fx].fldtype != CHRTYP) || ((fptr->flds[fx].fldtype == DATTYP) && (fptr->flds[fx].fldlen == 4)))
  592.       {
  593.          nnum = nummasklen(fptr->flds[fx].fldmask);
  594.          ndec = decmasklen(fptr->flds[fx].fldmask);
  595.          tptr = c4dtoa(dtmp, nnum, ndec);
  596.          bytecpy(&keybuf[so], tptr, nnum);
  597.          keybuf[so+nnum] = '\0';
  598.          so += nnum;
  599.       }
  600.    }
  601.    return(so);                                      /* length of key string */
  602. }
  603.  
  604. /*
  605.  *  Find first record in the file
  606. */
  607. static int i_firstkey(fd_sys, buffer)
  608. int fd_sys;
  609. char *buffer;
  610. {
  611.    int errcode;
  612.  
  613.    i_selectinx(fd_sys, buffer);   /* ensure required file & index selected */
  614.  
  615.    if ((errcode = d4top()) != IOGOOD)
  616.       return((errcode == 3) ? IONOKEY : io_xlate(fd_sys, v4error, "CB4 FRST"));
  617.  
  618.    return(get_record(fd_sys, buffer, NEXT));
  619. }
  620.  
  621. /*
  622.  *  Find last physical record in the file
  623. */
  624. static int i_lastkey(fd_sys, buffer)
  625. int fd_sys;
  626. char *buffer;
  627. {
  628.    int errcode;
  629.  
  630.    i_selectinx(fd_sys, buffer);   /* ensure required file & index selected */
  631.  
  632.    if (d4reccount() == 0L)     /* empty file returns EOF for auto numbering */
  633.       return(IOEOF);
  634.  
  635.    if ((errcode = d4bottom()) != IOGOOD)
  636.       return((errcode == 3) ? IONOKEY : io_xlate(fd_sys, v4error, "CB4 LAST"));
  637.  
  638.    return(get_record(fd_sys, buffer, PREV));
  639. }
  640.  
  641. /*
  642.  *  Find next record in the file
  643. */
  644. static int i_nextrec(fd_sys, buffer)
  645. int fd_sys;
  646. char *buffer;
  647. {
  648.    int errcode;
  649.     
  650.    i_selectinx(fd_sys, buffer);   /* ensure required file & index selected */
  651.    i_unlock_rec(fd_sys, buffer);   /* unlock current rec before proceeding */
  652.  
  653.    if ((errcode = d4skip(1L)) != IOGOOD)
  654.       return((errcode == 3) ? IOEOF : io_xlate(fd_sys, v4error, "CB4 NEXT"));
  655.    
  656.    return(get_record(fd_sys, buffer, NEXT));
  657. }
  658.  
  659. /*
  660.  *  Find previous record in the file
  661. */
  662. static int i_prevrec(fd_sys, buffer)
  663. int fd_sys;
  664. char *buffer;
  665. {
  666.    int errcode;
  667.     
  668.    i_selectinx(fd_sys, buffer);   /* ensure required file & index selected */
  669.    i_unlock_rec(fd_sys, buffer);   /* unlock current rec before proceeding */
  670.  
  671.    if ((errcode = d4skip(-1L)) != IOGOOD)
  672.       return((errcode == 1) ? IOTOF : io_xlate(fd_sys, v4error, "CB4 PREV"));
  673.    
  674.    return(get_record(fd_sys, buffer, PREV));
  675. }
  676.  
  677. /*
  678.  *  Retrieve a record, converting from CodeBase to PRO-C buffer format
  679.  *  - record locking is taken care of here
  680.  *  - if nextone is TRUE, will try next record when passing over a deleted
  681.  *    record; otherwise will try previous record
  682. */
  683. static int get_record(fd_sys, P_buff, nextone)
  684. int fd_sys, nextone;
  685. char *P_buff;
  686. {
  687.    int ofst, flen, lnum, i, so = 1;
  688.    int itmp;
  689.    long ltmp;
  690.    float ftmp;
  691.    double dtmp;
  692.    char stmp[20];
  693.    char *CB_buff, memobuff[MAX_FLDLEN + 1];
  694.    struct fd_def *fptr = &fd[fd_sys];
  695.    struct dbf_def *dptr = &fdbf[fd_sys];
  696.  
  697.    if (i_lockrec(fd_sys, P_buff) != IOGOOD)
  698.       return(IOERROR);
  699.  
  700.    CB_buff = (char *)f4record();          /* ptr to CodeBase record buffer */
  701.  
  702.    if (!*CB_buff)
  703.       return(io_xlate(fd_sys, v4error, "CB4 GETREC"));
  704.  
  705.    if (CB_buff[0] == DBFINACT)      /* if a deleted file, go to next record */
  706.       return(nextone ? i_nextrec(fd_sys, P_buff) : i_prevrec(fd_sys, P_buff));
  707.  
  708.    dptr->recnum = d4recno();
  709.  
  710.    zerorec(P_buff, fptr->rec_len);
  711.    
  712.    for (i = 0; i < fptr->fld_cnt; i++)
  713.    {
  714.       ofst = fptr->flds[i].fldstart;
  715.       flen = fptr->flds[i].fldlen;
  716.       lnum = nummasklen(fptr->flds[i].fldmask);
  717.  
  718.       switch(fptr->flds[i].fldtype)
  719.       {
  720.          case DATTYP :
  721.                 if (flen == 6)
  722.             {
  723.                so += 2;                      /* ignore the "19" in the date */
  724.                 strncpy(&P_buff[ofst], &CB_buff[so], flen);
  725.                 stripright(&P_buff[ofst], flen);
  726.                 so += flen;                         /* offset for next field */
  727.                 break;
  728.                 }
  729.                 else              /* for long int date type fall thru to LNGTYP */
  730.                     lnum = 10;
  731.          case LNGTYP :                               /* don't move this !!! */
  732.             ltmp = c4atol(&CB_buff[so], lnum);
  733.             bytecpy(&P_buff[ofst], <mp, flen);
  734.             so += lnum;
  735.             break;
  736.          case CHRTYP :
  737.             strncpy(&P_buff[ofst], &CB_buff[so], flen);
  738.             stripright(&P_buff[ofst], flen);
  739.             so += flen;                            /* offset for next field */
  740.             break;
  741.          case INTTYP :
  742.             itmp = c4atoi(&CB_buff[so], lnum);
  743.             bytecpy(&P_buff[ofst], &itmp, flen);
  744.             so += lnum;
  745.             break;
  746.          case FLTTYP :
  747.             dtmp = c4atod(&CB_buff[so], lnum);
  748.             ftmp = (float)dtmp;
  749.             bytecpy(&P_buff[ofst], &ftmp, flen);
  750.             so += lnum;
  751.             break;
  752.          case DBLTYP :
  753.             dtmp = c4atod(&CB_buff[so], lnum);
  754.             bytecpy(&P_buff[ofst], &dtmp, flen);
  755.             so += lnum;
  756.             break;
  757.          case LOGTYP :
  758.             P_buff[ofst] = CB_buff[so];
  759.             so += 1;
  760.             break;
  761.          case MEMTYP :
  762.             so += 10;                       /* placepointer in CB_buff only */
  763.             if (m3exist(dptr->fld_ref[i]))
  764.             {
  765.                if (m3read(dptr->fld_ref[i], dptr->recnum, memobuff, flen) == -1)
  766.                   errmsg(FileMemoNoRead_ss, fptr->flds[i].fldname, fptr->filname);
  767.                strcpy(&P_buff[ofst], memobuff);
  768.             }
  769.             break;
  770.       }
  771.    }
  772.    return(IOGOOD);
  773. }
  774.  
  775. /*
  776.  *  Re-read/reposition record pointer function - if required
  777. */
  778. static int i_rereadrec(fd_sys, buffer)
  779. int fd_sys;
  780. char *buffer;
  781. {
  782.    return(i_findkey(fd_sys, buffer));
  783. }
  784.  
  785.  
  786. /*
  787.  *  Add a new record.
  788.  *  - uses put_record() with record number = 0 to enable appending
  789. */
  790. static int i_addrec(fd_sys, buffer)
  791. int fd_sys;
  792. char *buffer;
  793. {
  794.    fdbf[fd_sys].recnum = 0L;
  795.    return(put_record(fd_sys, buffer));
  796. }
  797.  
  798. /*
  799.  *  Update the current record.
  800. */
  801. static int i_updrec(fd_sys, buffer)
  802. int fd_sys;
  803. char *buffer;
  804. {
  805.    return(put_record(fd_sys, buffer));
  806. }
  807.  
  808. /*
  809.  *  Write a record, converting from PRO-C buffer format to CodeBase 
  810.  *  - this function appends a blank record if called from addrec
  811.  *  - memo fields are written as they occur
  812.  *  - locking and updating of index files is automatic with d4write
  813. */
  814. static int put_record(fd_sys, P_buff)
  815. int fd_sys;
  816. char *P_buff;
  817. {
  818.    int errcode, ofst, flen, lnum, ldec, i, j, so = 1;
  819.    char *ptr;
  820.    int itmp;
  821.    long ltmp;
  822.    float ftmp;
  823.    double dtmp;
  824.    char *CB_buff, tbuff[MAX_RECLEN], memobuff[MAX_FLDLEN + 1];
  825.    struct fd_def *fptr = &fd[fd_sys];
  826.    struct dbf_def *dptr = &fdbf[fd_sys];
  827.  
  828.    i_selectinx(fd_sys, P_buff);        /* ensure required file is selected */
  829.    d4go(0L);                            /* blank the CodeBase record buffer */
  830.    CB_buff = (char *)f4record();
  831.  
  832.    if (dptr->recnum == 0L)               /* if a new record, append a blank */
  833.    {
  834.       if ((errcode = d4write(0L)) != IOGOOD)
  835.          return((errcode == -2) ? IODUP : io_xlate(fd_sys, v4error, "CB4 ADD"));
  836.       dptr->recnum = d4recno();
  837.    }
  838.  
  839.    for (i = 0; i < fptr->fld_cnt; i++)
  840.    {
  841.       ofst = fptr->flds[i].fldstart;
  842.       flen = fptr->flds[i].fldlen;
  843.       lnum = nummasklen(fptr->flds[i].fldmask);
  844.       ldec = decmasklen(fptr->flds[i].fldmask);
  845.  
  846.       switch(fptr->flds[i].fldtype)
  847.       {
  848.          case DATTYP :
  849.                 if (flen == 6)
  850.             {
  851.                if (!P_buff[ofst])
  852.                   strcpy(tbuff, "19000101");
  853.                else
  854.                {
  855.                   strcpy(tbuff, "19");                 /* dBASE date format */
  856.                   strncat(tbuff, &P_buff[ofst], flen);
  857.                }
  858.                 strncpy(&CB_buff[so], tbuff, 8);
  859.                 so += 8;
  860.                 break;
  861.                 }
  862.                 else              /* for long int date type fall thru to LNGTYP */
  863.                     lnum = 10;
  864.          case LNGTYP :                               /* don't move this !!! */
  865.             bytecpy(<mp, &P_buff[ofst], flen); 
  866.             c4ltoa(ltmp, &CB_buff[so], lnum);
  867.             so += lnum;
  868.             break;
  869.          case CHRTYP :
  870.             strncpy(&CB_buff[so], &P_buff[ofst], flen);
  871.             for (j = strlen(&P_buff[ofst]); j < flen; j++)
  872.                CB_buff[j+so] = ' ';                      /* pad with spaces */
  873.             so += flen;                            /* offset for next field */
  874.             break;
  875.          case INTTYP :
  876.             bytecpy(&itmp, &P_buff[ofst], flen);
  877.             c4ltoa((long)itmp, &CB_buff[so], lnum);
  878.             so += lnum;
  879.             break;
  880.          case FLTTYP :
  881.             bytecpy(&ftmp, &P_buff[ofst], flen);
  882.             ptr = c4dtoa((double)ftmp, lnum, ldec);
  883.             strncpy(&CB_buff[so], ptr, lnum);
  884.             so += lnum;
  885.             break;
  886.          case DBLTYP :
  887.             bytecpy(&dtmp, &P_buff[ofst], flen);
  888.             ptr = c4dtoa(dtmp, lnum, ldec);
  889.             strncpy(&CB_buff[so], ptr, lnum);
  890.             so += lnum;
  891.             break;
  892.          case LOGTYP :
  893.             CB_buff[so] = P_buff[ofst];
  894.             so += 1;
  895.             break;
  896.          case MEMTYP :
  897.             if (P_buff[ofst])                    /* memo field is not empty */
  898.             {
  899.                memset(&CB_buff[so], 0, 10);      /* FOR NOW holds the place */
  900.                strcpy(memobuff, &P_buff[ofst]);
  901.                memcpy(tbuff, CB_buff, fptr->rec_len);
  902.                if (m3write(dptr->fld_ref[i], dptr->recnum, memobuff, flen) == -1)
  903.                   errmsg(FileMemoNoWrite_ss, fptr->flds[i].fldname, fptr->filname);
  904.                memcpy(&tbuff[so], &CB_buff[so], 10);   /* save memo pointer */
  905.                memcpy(CB_buff, tbuff, fptr->rec_len);    /* restore CB_buff */
  906.             }
  907.             so += 10;
  908.             break;
  909.       }
  910.    }
  911.    if ((errcode = d4write(dptr->recnum)) != IOGOOD)
  912.       return((errcode == -2) ? IODUP : io_xlate(fd_sys, v4error, "CB4 UPD"));
  913.    return(IOGOOD);
  914. }
  915.  
  916.  
  917. static struct optab pconf[] = {
  918.     { 2,  34, "No " },
  919.     { 2,  34, "Yes" },
  920.     { NORMAL, REVVID, NULL }
  921. };
  922.  
  923.  
  924. /*
  925.  *  Delete the current record.
  926.  *  - locking and updating of index files is automatic with d4write
  927.  *  - PACK is optional, will reindex open index files
  928. */
  929. static int i_delrec(fd_sys, buffer)
  930. int fd_sys;
  931. char *buffer;
  932. {
  933.    int errcode, rslt;
  934.  
  935.    i_selectinx(fd_sys, buffer);   /* ensure required file & index selected */
  936.  
  937.    if ((errcode = d4delete(fdbf[fd_sys].recnum)) != IOGOOD)
  938.       return((errcode == 1) ? IONOKEY : io_xlate(fd_sys, v4error, "CB4 DEL"));
  939.  
  940. #ifdef ALLOW_PACKING
  941.    create_w(11, 19, 3, 40);
  942.    border_w(boxset, BOLD);
  943.    disp_w(2, 3, NORMAL, "Do you want to PACK the file?  ");
  944.    rslt = do_options(pconf, rslt, 0);
  945.    if (ichar == K_ESC)
  946.       rslt = FALSE;
  947.    delete_w();
  948.    if (rslt)
  949.       if (d4pack())
  950.          errmsg(FilePackFail_s, fd[fd_sys].filname);
  951. #endif
  952.  
  953.    return(IOGOOD);
  954. }
  955.  
  956.  
  957. /*
  958.  *  Lock Record
  959. */  
  960. static int i_lockrec(fd_sys, buffer)
  961. int fd_sys;
  962. char *buffer;
  963. {
  964.    int errcode = -1;
  965.  
  966.    if ((fd[fd_sys].lockmode == NOLOCK) || (fdbf[fd_sys].recnum == 0L))
  967.       return(IOGOOD);                     /* no retry if recnum not defined */
  968.  
  969.    errcode = d4lock(fdbf[fd_sys].recnum, 0);      /* lock on current record */
  970.  
  971.    if (errcode == -2)
  972.       return(IOLOCKED);
  973.    if (errcode == -1)
  974.       return(io_xlate(fd_sys, v4error, "CB4 LOCK"));
  975.  
  976.    return(errcode ? IONOKEY : IOGOOD);      /* errcode 0 if lock successful */
  977. }
  978.  
  979. /*
  980.  *  Unlock Record
  981.  *  - d4unlock does not unlock index files, so this must be done manually
  982. */
  983. static int i_unlock_rec(fd_sys, buffer)
  984. int fd_sys;
  985. char *buffer;
  986. {
  987.    int errcode;
  988.  
  989.    if (fd[fd_sys].lockmode == NOLOCK)
  990.       return(IOGOOD);
  991.  
  992.    if ((errcode = d4unlock((long)-1)) == CBERROR)
  993.       return io_xlate(fd_sys, v4error, "CB4 ULOCK1");
  994.  
  995.    if ((errcode = i4unlock(-1)) == CBERROR)
  996.       return io_xlate(fd_sys, v4error, "CB4 ULOCK2");
  997.  
  998.    return(IOGOOD);
  999. }
  1000.  
  1001.  
  1002. /*
  1003.  *  Login
  1004. */
  1005. static int i_login(fd_sys, buffer)
  1006. int fd_sys;
  1007. char *buffer;
  1008. {
  1009.    return(IOGOOD);
  1010. }
  1011.  
  1012. /*
  1013.  *  Logoff
  1014. */
  1015. static int i_logoff(fd_sys, buffer)
  1016. int fd_sys;
  1017. char *buffer;
  1018. {
  1019.    return(IOGOOD);
  1020. }
  1021.  
  1022. /*
  1023.  *  End (Commit) transaction 
  1024. */
  1025. static int i_commit(fd_sys, buffer)
  1026. int fd_sys;
  1027. char *buffer;
  1028. {
  1029.    return(IOGOOD);
  1030. }
  1031.  
  1032. /*
  1033.  *  Rollback transaction
  1034. */
  1035. static int i_rollback(fd_sys, buffer)
  1036. int fd_sys;
  1037. char *buffer;
  1038. {
  1039.    return(IOGOOD);
  1040. }
  1041.  
  1042. /*
  1043.  *  Start transaction
  1044. */
  1045. static int i_transact(fd_sys, buffer)
  1046. int fd_sys;
  1047. char *buffer;
  1048. {
  1049.    return(IOGOOD);
  1050. }
  1051.  
  1052. /*
  1053.  *  This routine translates CodeBase Error codes into PRO-C error codes.
  1054.  *  If no PRO-C equivalent, displays the error number.
  1055. */
  1056. static int io_xlate(fd_sys, ernum, rtnname)
  1057. int fd_sys;
  1058. int ernum;
  1059. char *rtnname;
  1060. {
  1061.    switch(ernum)
  1062.    {
  1063.       case  120  :
  1064.          return IOBADOPEN;
  1065.       case  200  :
  1066.       case  240  :
  1067.       case  320  :
  1068.          return IONOFILE;
  1069.       case  330  :
  1070.       case  380  :
  1071.          return IONOKEY;
  1072.       case  400  :
  1073.          return IOLOCKED;
  1074.       case  450  :
  1075.          return IONOLOCK;
  1076.    }
  1077.  
  1078.    if (fd_sys > 0)
  1079.       errmsg(FileDbgError_sdss, "CodeBase", ernum, fd[fd_sys].filname, rtnname);
  1080.    else      /* if routines called from generated apps without valid fd_sys */
  1081.       errmsg(FileDbgError_sds, "CodeBase", ernum, rtnname);
  1082.    return(IOERROR);
  1083. }
  1084.  
  1085.  
  1086. void assign_IO_CL(dbnum)
  1087. {
  1088.    assign_IO_CB(dbnum);
  1089.    enable_clipper = TRUE;
  1090. }
  1091.  
  1092.  
  1093. /*
  1094.  * Assign section
  1095. */
  1096.  
  1097. void assign_IO_CB(dbnum)
  1098. int dbnum;
  1099. {
  1100.    Fntab[dbnum - 1][0]  = (int(*)())0; /* Empty */
  1101.    Fntab[dbnum - 1][1]  = i_init_file;
  1102.    Fntab[dbnum - 1][2]  = i_open_file;
  1103.    Fntab[dbnum - 1][3]  = i_close_file;
  1104.    Fntab[dbnum - 1][4]  = i_addrec;
  1105.    Fntab[dbnum - 1][5]  = i_delrec;
  1106.    Fntab[dbnum - 1][6]  = i_findkey;
  1107.    Fntab[dbnum - 1][7]  = i_firstkey;
  1108.    Fntab[dbnum - 1][8]  = i_lastkey;
  1109.    Fntab[dbnum - 1][9]  = i_lockrec;
  1110.    Fntab[dbnum - 1][10] = i_nextrec;
  1111.    Fntab[dbnum - 1][11] = i_prevrec;
  1112.    Fntab[dbnum - 1][12] = i_unlock_rec;
  1113.    Fntab[dbnum - 1][13] = i_updrec;
  1114.    Fntab[dbnum - 1][14] = i_commit;
  1115.    Fntab[dbnum - 1][15] = i_login;
  1116.    Fntab[dbnum - 1][16] = i_logoff;
  1117.    Fntab[dbnum - 1][17] = i_rollback;
  1118.    Fntab[dbnum - 1][18] = i_transact;
  1119.    Fntab[dbnum - 1][19] = i_selectinx;
  1120.    Fntab[dbnum - 1][20] = i_rereadrec;
  1121.    Fntab[dbnum - 1][21] = i_filename;
  1122.    enable_clipper = FALSE;
  1123. }
  1124.  
  1125.