home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / database / db12 / db_main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-11-23  |  34.8 KB  |  1,365 lines

  1. /****************************************************************************/
  2. /*                                                                          */
  3. /*                                                                          */
  4. /*      db_main.c     (c) 1987  Ken Harris                                  */
  5. /*                                                                          */
  6. /*                                                                          */
  7. /****************************************************************************/
  8. /*                                                                          */
  9. /*      This software is made available on an AS-IS basis. Unrestricted     */
  10. /*      use is granted provided that the copywrite notice remains intack.   */
  11. /*      The author makes no warranties expressed or implied.                */
  12. /*                                                                          */
  13. /****************************************************************************/
  14.  
  15. #include <stdio.h>
  16. #ifdef MSC
  17. #include <fcntl.h>
  18. #include <sys\types.h>
  19. #include <sys\stat.h>
  20. #endif
  21. #include "db.h"
  22.  
  23. static char  *copyright = "db V1.2 (c) 1987 Ken Harris";
  24.  
  25. int    db_error     = 0;
  26. ulong  db_match_blk = 0;
  27. ushort db_match_rec = 0;
  28. ulong  db_add_blk   = 0;
  29. ushort db_add_rec   = 0;
  30.  
  31. /*
  32.  *      db_create  -  Create a New Data Set
  33.  */
  34.  
  35. DATA_SET db_create(path, fname, fhdr)
  36.  char *path, *fname;               
  37.  FILE_HDR fhdr;
  38. {
  39.         BUFFER db_alloc_buf();
  40.         DATA_SET ds;
  41.         char  *fname_dflts(), *calloc();
  42.  
  43.         db_error = 0;
  44.  
  45.         db_fhdr_create(fhdr);
  46.         if (db_error) return(NULL);
  47.  
  48.         ds = (DATA_SET) calloc(1, sizeof(struct db_data_set));
  49.  
  50.         strcpy(ds->ds_fname, fname_dflts(fname,path));
  51.  
  52. #ifdef MSC
  53.     ds->ds_fd = open(ds->ds_fname, O_CREAT|O_TRUNC|O_RDWR|O_BINARY, S_IREAD|S_IWRITE);
  54. #endif
  55. #ifdef CI86
  56.         ds->ds_fd = creat(ds->ds_fname, BUPDATE);
  57. #endif    
  58.         if (ds->ds_fd < 0)
  59.         {       db_error = DB_FILE_NOT_CREATED;
  60.                 db_free_ds(ds);
  61.                 return(NULL);
  62.         }                       
  63.  
  64.         ds->ds_stat = DB_OPEN;
  65.  
  66.         ds->ds_fhdr               = db_alloc_buf(0);
  67.         ds->ds_fhdr->buf_size     = sizeof(struct db_file_hdr);
  68.         ds->ds_fhdr->buf_data     = (char*) fhdr;
  69.         ds->ds_fhdr->buf_cur_size = sizeof(struct db_file_hdr);
  70.  
  71.         if (fhdr->fh_file_type == DB_INDEX)
  72.         {    ds->ds_buf = db_alloc_buf(fhdr->fh_block_size + 2 * fhdr->fh_rec_size);
  73.              ds->ds_tmp = db_alloc_buf(fhdr->fh_block_size + 2 * fhdr->fh_rec_size);
  74.              ds->ds_aux = db_alloc_buf(fhdr->fh_block_size + 2 * fhdr->fh_rec_size);
  75.              ds->ds_buf->buf_size = fhdr->fh_block_size;
  76.              ds->ds_tmp->buf_size = fhdr->fh_block_size;
  77.              ds->ds_aux->buf_size = fhdr->fh_block_size;
  78.         }
  79.         else
  80.         if (fhdr->fh_file_type == DB_RANDOM)
  81.         {    ds->ds_buf = db_alloc_buf(fhdr->fh_block_size);
  82.              ds->ds_tmp = db_alloc_buf(fhdr->fh_block_size);
  83.              while (fhdr->fh_last_block < fhdr->fh_base_size)
  84.              {  db_extend(ds, ds->ds_buf);
  85.         if (db_error) return(NULL);
  86.  
  87.                 db_put_blk(ds, ds->ds_buf);
  88.              }
  89.         }
  90.         else
  91.              ds->ds_buf = db_alloc_buf(fhdr->fh_block_size);
  92.  
  93.         db_put_blk(ds, ds->ds_fhdr);
  94.         if (db_error)
  95.         {       db_free_ds(ds);
  96.                 return(NULL);
  97.         }
  98.  
  99.         return(ds);
  100. }
  101.  
  102. /*
  103.  *      db_fhdr_create - Check file header data on create
  104.  */
  105.  
  106. void db_fhdr_create(fh)
  107.  FILE_HDR fh;
  108. {       short hdr_size;
  109.  
  110.         db_error = 0;
  111.  
  112.         fh->fh_db_version = DB_VERSION;
  113.  
  114.         if (fh->fh_file_type != DB_SEQ    &&
  115.             fh->fh_file_type != DB_RANDOM &&
  116.             fh->fh_file_type != DB_INDEX)
  117.         {       db_error = DB_INVALID_FHDR;
  118.                 return;
  119.         }
  120.  
  121.     fh->fh_file_stat &= ~DB_OPEN;
  122.         fh->fh_last_block = 0;
  123.  
  124.         if (!fh->fh_block_size) fh->fh_block_size = 512;
  125.  
  126.         switch (fh->fh_file_type)
  127.         {       case DB_SEQ:
  128.                      hdr_size = 0;
  129.                      if (!fh->fh_ctl_size) fh->fh_ctl_size = 1;
  130.                      break;
  131.  
  132.                 case DB_RANDOM:
  133.                      hdr_size = sizeof(struct db_random_hdr);
  134.                      if (!fh->fh_base_size)
  135.                      {       db_error = DB_INVALID_FHDR;
  136.                              return;
  137.                      }
  138.                      if (!fh->fh_ctl_size) fh->fh_ctl_size = 1;
  139.                      break;
  140.  
  141.                 case DB_INDEX:
  142.                      hdr_size = sizeof(struct db_index_hdr);
  143.                      if (!fh->fh_ctl_size) fh->fh_ctl_size = 2;
  144.                      break;
  145.  
  146.                 default:
  147.                      hdr_size = 0;
  148.                      break;
  149.         }
  150.  
  151.         fh->fh_rec_size     = fh->fh_ctl_size + fh->fh_data_size;
  152.  
  153.     if (fh->fh_block_size < fh->fh_rec_size + hdr_size)
  154.         fh->fh_block_size = fh->fh_rec_size + hdr_size;
  155.  
  156.     fh->fh_block_size = ((fh->fh_block_size + 511) / 512) * 512;
  157.  
  158.         fh->fh_rec_cnt      = 0;
  159.         fh->fh_recs_per_blk = (fh->fh_block_size - hdr_size) / fh->fh_rec_size;
  160.         fh->fh_root_ptr     = 0;
  161.         fh->fh_next_avail   = 0;
  162.  
  163.         if (fh->fh_key_size > fh->fh_data_size)
  164.         {       db_error = DB_INVALID_FHDR;
  165.                 return;
  166.         }
  167. }
  168.  
  169. /*
  170.  *      db_open  -  Open a Data Set
  171.  */
  172.  
  173. DATA_SET db_open(path,fname)
  174.  char *path, *fname;
  175. {
  176.         BUFFER   db_alloc_buf();
  177.         DATA_SET ds;
  178.         FILE_HDR fhdr;
  179.         char    *fname_dflts(), *calloc();
  180.         int      cnt;
  181.  
  182.         db_error = 0;
  183.         ds = (DATA_SET) calloc(1, sizeof(struct db_data_set));
  184.         strcpy(ds->ds_fname, fname_dflts(fname,path));
  185.  
  186. #ifdef MSC
  187.         ds->ds_fd = open(ds->ds_fname, O_RDWR|O_BINARY);
  188. #endif
  189. #ifdef CI86
  190.         ds->ds_fd = open(ds->ds_fname, BUPDATE);
  191. #endif
  192.         if (ds->ds_fd < 0)
  193.         {       db_error = DB_FILE_NOT_FOUND;
  194.                 db_free_ds(ds);
  195.                 return(NULL);
  196.         }
  197.                 
  198.         ds->ds_stat = DB_OPEN;
  199.  
  200.         ds->ds_fhdr = db_alloc_buf(sizeof(struct db_file_hdr));
  201.         fhdr = (FILE_HDR) ds->ds_fhdr->buf_data;
  202.             
  203.         db_get_blk(ds, 0L, ds->ds_fhdr);
  204.         if (db_error)
  205.         {       db_free_ds(ds);
  206.                 return(NULL);
  207.         }
  208.         
  209.         db_fhdr_open(fhdr);
  210.         if (db_error) return(NULL);
  211.  
  212.         if (fhdr->fh_file_type == DB_INDEX)
  213.         {    ds->ds_buf = db_alloc_buf(fhdr->fh_block_size + 2 * fhdr->fh_rec_size);
  214.              ds->ds_tmp = db_alloc_buf(fhdr->fh_block_size + 2 * fhdr->fh_rec_size);
  215.              ds->ds_aux = db_alloc_buf(fhdr->fh_block_size + 2 * fhdr->fh_rec_size);
  216.              ds->ds_buf->buf_size = fhdr->fh_block_size;
  217.              ds->ds_tmp->buf_size = fhdr->fh_block_size;
  218.              ds->ds_aux->buf_size = fhdr->fh_block_size;
  219.         }
  220.         else
  221.         if (fhdr->fh_file_type == DB_RANDOM)
  222.         {    ds->ds_buf = db_alloc_buf(fhdr->fh_block_size);
  223.              ds->ds_tmp = db_alloc_buf(fhdr->fh_block_size);
  224.         }
  225.         else
  226.              ds->ds_buf = db_alloc_buf(fhdr->fh_block_size);
  227.  
  228.         return(ds);
  229. }
  230.  
  231. /*
  232.  *      db_fhdr_open - Check file header data on open
  233.  */
  234.  
  235. void db_fhdr_open(fh)
  236.  FILE_HDR fh;
  237. {
  238.         db_error = 0;
  239.  
  240.         if (fh->fh_db_version != DB_VERSION)
  241.         {       db_error = DB_VERSION_ERROR;
  242.                 return;
  243.         }
  244.  
  245.         if (fh->fh_file_type != DB_SEQ    &&
  246.             fh->fh_file_type != DB_RANDOM &&
  247.             fh->fh_file_type != DB_INDEX)
  248.         {       db_error = DB_INVALID_FHDR;
  249.                 return;
  250.         }
  251.  
  252.         if (fh->fh_block_size   == 0 ||
  253.             fh->fh_rec_size     == 0 ||
  254.             fh->fh_recs_per_blk == 0)
  255.         {       db_error = DB_INVALID_FHDR;
  256.                 return;
  257.         }
  258.  
  259.         if (fh->fh_rec_size != fh->fh_ctl_size + fh->fh_data_size)
  260.         {       db_error = DB_INVALID_FHDR;
  261.                 return;
  262.         }
  263.  
  264.         if (fh->fh_key_size > fh->fh_data_size)
  265.         {       db_error = DB_INVALID_FHDR;
  266.                 return;
  267.         }
  268.  
  269.         if (fh->fh_file_type == DB_RANDOM &&
  270.             fh->fh_base_size == 0)
  271.         {       db_error = DB_INVALID_FHDR;
  272.                 return;
  273.         }
  274. }
  275.  
  276. /*
  277.  *      db_close  -  close a data set
  278.  */
  279.  
  280. DATA_SET db_close(ds)
  281.  DATA_SET ds;
  282. {
  283.         db_error = 0;
  284.  
  285.         db_check_ds(ds);
  286.     if (db_error) return(NULL);
  287.  
  288.         db_put_blk(ds, ds->ds_fhdr);
  289.     if (db_error) return(NULL);
  290.  
  291.         close(ds->ds_fd);
  292.  
  293.         db_free_ds(ds);
  294.  
  295.         return(NULL);
  296. }
  297.  
  298. /*
  299.  *      db_add  -  Add a new record to a data set
  300.  */
  301.  
  302. ulong db_add(ds, user_data)
  303.  DATA_SET ds;
  304.  char *user_data;
  305. {
  306.         FILE_HDR fh;
  307.         BUFFER  buf;
  308.         ulong   rec_no;
  309.  
  310.         db_error = 0;
  311.  
  312.         db_check_ds(ds);
  313.         if (db_error) return(0);
  314.  
  315.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  316.         buf = (BUFFER) ds->ds_buf;
  317.  
  318.         switch (fh->fh_file_type)
  319.         {       case DB_SEQ:
  320.                         db_add_seq(ds, user_data);
  321.                         break;
  322.  
  323.                 case DB_INDEX:
  324.                         db_add_idx(ds, user_data);
  325.                         break;
  326.  
  327.                 case DB_RANDOM:
  328.                         db_add_ran(ds, user_data);
  329.                         break;
  330.  
  331.                 default:
  332.                         db_error = DB_INVALID_REQUEST;
  333.                         break;
  334.         }
  335.  
  336.         if (db_error) return(0);
  337.  
  338.         rec_no = (db_add_blk - 1) * fh->fh_recs_per_blk + db_add_rec;
  339.  
  340.         buf->buf_cur_blk = 0;
  341.         buf->buf_rec_inx = 0;
  342.  
  343.         return(rec_no);
  344. }
  345.  
  346. /*
  347.  *      db_read_first  -  Read First Record in a data set
  348.  */
  349.  
  350. void db_read_first(ds, user_data)
  351.  DATA_SET ds;
  352.  char *user_data;
  353. {
  354.         FILE_HDR  fh;
  355.         BUFFER   buf;
  356.  
  357.         db_error = 0;
  358.  
  359.         db_check_ds(ds);
  360.         if (db_error) return;
  361.  
  362.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  363.         buf = (BUFFER) ds->ds_buf;
  364.  
  365.         if (!fh->fh_rec_cnt)
  366.         {       db_error = DB_END_OF_FILE;
  367.                 return;
  368.         }
  369.  
  370.         switch (fh->fh_file_type)
  371.         {       case DB_SEQ:
  372.                         db_read_first_seq(ds, user_data);
  373.                         break;
  374.  
  375.                 case DB_INDEX:
  376.                         db_read_first_idx(ds, fh->fh_root_ptr, user_data);
  377.                         break;
  378.  
  379.                 case DB_RANDOM:
  380.                         db_read_first_ran(ds, user_data);
  381.                         break;
  382.  
  383.                 default:
  384.                         db_error = DB_INVALID_REQUEST;
  385.                         break;
  386.         }
  387.  
  388.         if (db_error)
  389.         {       buf->buf_cur_blk = 0;
  390.                 buf->buf_rec_inx = 0;
  391.         }
  392.  
  393.         ds->ds_prev_blk = buf->buf_cur_blk;
  394.         ds->ds_prev_rec = buf->buf_rec_inx;
  395.  
  396.     return;
  397. }
  398.  
  399. /*
  400.  *      db_read_next  -  Read next record from a data set
  401.  */
  402.  
  403. void db_read_next(ds, user_data)
  404.  DATA_SET ds;
  405.  char *user_data;
  406. {
  407.         FILE_HDR  fh;
  408.         BUFFER   buf;
  409.  
  410.         db_error = 0;
  411.  
  412.         db_check_ds(ds);
  413.         if (db_error) return;
  414.  
  415.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  416.         buf = (BUFFER) ds->ds_buf;
  417.  
  418.         if (!fh->fh_rec_cnt)
  419.         {       db_error = DB_END_OF_FILE;
  420.                 return;
  421.         }
  422.  
  423.         if (!ds->ds_prev_blk)
  424.         {       db_error = DB_NO_CURRENT_REC;
  425.                 return;
  426.         }
  427.  
  428.         switch (fh->fh_file_type)
  429.         {       case DB_SEQ:
  430.                         db_read_next_seq(ds, user_data);
  431.                         break;
  432.  
  433.                 case DB_INDEX:
  434.                         db_read_next_idx(ds, user_data);
  435.                         break;
  436.                               
  437.                 case DB_RANDOM:
  438.                         db_read_next_ran(ds, user_data);
  439.                         break;
  440.  
  441.                 default:
  442.                         db_error = DB_INVALID_REQUEST;
  443.                         break;
  444.         }
  445.  
  446.         if (db_error)
  447.         {       buf->buf_cur_blk = 0;
  448.                 buf->buf_rec_inx = 0;
  449.         }
  450.  
  451.         ds->ds_prev_blk = buf->buf_cur_blk;
  452.         ds->ds_prev_rec = buf->buf_rec_inx;
  453.  
  454.     return;
  455. }
  456.  
  457. /*
  458.  *    db_read_last  -  Read Last Record in a data set
  459.  */
  460.  
  461. void db_read_last(ds, user_data)
  462.  DATA_SET ds;
  463.  char *user_data;
  464. {
  465.         FILE_HDR  fh;
  466.         BUFFER   buf;
  467.  
  468.         db_error = 0;
  469.  
  470.         db_check_ds(ds);
  471.         if (db_error) return;
  472.  
  473.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  474.         buf = (BUFFER) ds->ds_buf;
  475.  
  476.         if (!fh->fh_rec_cnt)
  477.         {       db_error = DB_END_OF_FILE;
  478.                 return;
  479.         }
  480.  
  481.         switch (fh->fh_file_type)
  482.         {       case DB_SEQ:
  483.             db_read_last_seq(ds, user_data);
  484.                         break;
  485.  
  486.                 case DB_INDEX:
  487.             db_read_last_idx(ds, fh->fh_root_ptr, user_data);
  488.                         break;
  489.  
  490.                 case DB_RANDOM:
  491.             db_read_last_ran(ds, user_data);
  492.                         break;
  493.  
  494.                 default:
  495.                         db_error = DB_INVALID_REQUEST;
  496.                         break;
  497.         }
  498.  
  499.         if (db_error)
  500.         {       buf->buf_cur_blk = 0;
  501.                 buf->buf_rec_inx = 0;
  502.         }
  503.  
  504.         ds->ds_prev_blk = buf->buf_cur_blk;
  505.         ds->ds_prev_rec = buf->buf_rec_inx;
  506.  
  507.     return;
  508. }
  509.  
  510. /*
  511.  *    db_read_prev  -  Read prev record from a data set
  512.  */
  513.  
  514. void db_read_prev(ds, user_data)
  515.  DATA_SET ds;
  516.  char *user_data;
  517. {
  518.         FILE_HDR  fh;
  519.         BUFFER   buf;
  520.  
  521.         db_error = 0;
  522.  
  523.         db_check_ds(ds);
  524.         if (db_error) return;
  525.  
  526.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  527.         buf = (BUFFER) ds->ds_buf;
  528.  
  529.         if (!fh->fh_rec_cnt)
  530.         {       db_error = DB_END_OF_FILE;
  531.                 return;
  532.         }
  533.  
  534.         if (!ds->ds_prev_blk)
  535.         {       db_error = DB_NO_CURRENT_REC;
  536.                 return;
  537.         }
  538.  
  539.         switch (fh->fh_file_type)
  540.         {       case DB_SEQ:
  541.             db_read_prev_seq(ds, user_data);
  542.                         break;
  543.  
  544.                 case DB_INDEX:
  545.             db_read_prev_idx(ds, user_data);
  546.                         break;
  547.                               
  548.                 case DB_RANDOM:
  549.             db_read_prev_ran(ds, user_data);
  550.                         break;
  551.  
  552.                 default:
  553.                         db_error = DB_INVALID_REQUEST;
  554.                         break;
  555.         }
  556.  
  557.         if (db_error)
  558.         {       buf->buf_cur_blk = 0;
  559.                 buf->buf_rec_inx = 0;
  560.         }
  561.  
  562.         ds->ds_prev_blk = buf->buf_cur_blk;
  563.         ds->ds_prev_rec = buf->buf_rec_inx;
  564.  
  565.     return;
  566. }
  567.  
  568. /*
  569.  *      db_find  -  Find a Record
  570.  */
  571.  
  572. void db_find(ds, user_data, key, key_size)
  573.  DATA_SET ds;
  574.  char *user_data;
  575.  char *key;
  576.  int   key_size;
  577. {
  578.         FILE_HDR  fh;
  579.         BUFFER   buf;
  580.  
  581.         db_error = 0;
  582.  
  583.         db_check_ds(ds);
  584.         if (db_error) return;
  585.  
  586.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  587.         buf = (BUFFER) ds->ds_buf;
  588.  
  589.         if (!fh->fh_rec_cnt)
  590.         {       db_error = DB_REC_NOT_FOUND;
  591.                 return;
  592.         }
  593.  
  594.         if (!key_size) key_size = fh->fh_key_size;
  595.  
  596.         switch (fh->fh_file_type)
  597.         {       case DB_INDEX:
  598.                         db_find_first_idx(ds, user_data, key, key_size);
  599.                         break;
  600.  
  601.                 case DB_RANDOM:
  602.                         db_find_ran(ds, user_data, key);
  603.                         break;
  604.  
  605.                 default:
  606.                         db_error = DB_INVALID_REQUEST;
  607.                         break;
  608.         }
  609.  
  610.         if (db_error)
  611.         {       buf->buf_cur_blk = 0;
  612.                 buf->buf_rec_inx = 0;
  613.         }
  614.  
  615.         ds->ds_prev_blk = buf->buf_cur_blk;
  616.         ds->ds_prev_rec = buf->buf_rec_inx;
  617.  
  618.     return;
  619. }
  620.  
  621. /*
  622.  *      db_update  -  Update a record from a data set
  623.  */
  624.  
  625. void db_update(ds, user_data)
  626.  DATA_SET ds;
  627.  char *user_data;
  628. {
  629.         FILE_HDR  fh;
  630.         BUFFER   buf;
  631.  
  632.         db_error = 0;
  633.  
  634.         db_check_ds(ds);
  635.         if (db_error) return;
  636.  
  637.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  638.         buf = (BUFFER) ds->ds_buf;
  639.  
  640.         if (!buf->buf_cur_blk || !buf->buf_rec_inx)
  641.         {       db_error = DB_NO_CURRENT_REC;
  642.                 return;
  643.         }
  644.  
  645.         switch (fh->fh_file_type)
  646.         {       case DB_SEQ:
  647.                         db_update_seq(ds, user_data);
  648.                         break;
  649.  
  650.                 case DB_RANDOM:
  651.                         db_update_ran(ds, user_data);
  652.                         break;
  653.  
  654.                 case DB_INDEX:
  655.                         db_update_idx(ds, user_data);
  656.                         break;
  657.  
  658.                 default:
  659.                         db_error = DB_INVALID_REQUEST;
  660.                         break;
  661.         }
  662.  
  663.         buf->buf_cur_blk = 0;
  664.         buf->buf_rec_inx = 0;
  665.  
  666.     return;
  667. }
  668.  
  669. /*
  670.  *      db_delete  -  Delete a record from a data set
  671.  */
  672.  
  673. void db_delete(ds)
  674.  DATA_SET ds;
  675. {
  676.         FILE_HDR  fh;
  677.         BUFFER   buf;
  678.  
  679.         db_error = 0;
  680.  
  681.         db_check_ds(ds);
  682.         if (db_error) return;
  683.  
  684.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  685.         buf = (BUFFER) ds->ds_buf;
  686.  
  687.         if (!buf->buf_cur_blk || !buf->buf_rec_inx)
  688.         {       db_error = DB_NO_CURRENT_REC;
  689.                 return;
  690.         }
  691.  
  692.         switch (fh->fh_file_type)
  693.         {       case DB_SEQ:
  694.                         db_free_rec(ds, buf);
  695.                         if (db_error) return;
  696.  
  697.                         if (fh->fh_rec_cnt > 0) fh->fh_rec_cnt--;
  698.                         db_put_blk(ds, ds->ds_fhdr);
  699.                         break;
  700.  
  701.                 case DB_INDEX:
  702.                         db_delete_idx(ds);
  703.                         break;
  704.  
  705.                 case DB_RANDOM:
  706.                         db_delete_ran(ds);
  707.                         break;
  708.  
  709.                 default:
  710.                         db_error = DB_INVALID_REQUEST;
  711.                         break;
  712.         }
  713.  
  714.         buf->buf_cur_blk = 0;
  715.         buf->buf_rec_inx = 0;
  716.  
  717.     return;
  718. }
  719.  
  720. /*
  721.  *      db_get_rec_no  -  Get relative record number
  722.  */
  723.  
  724. ulong db_get_rec_no(ds)
  725.  DATA_SET ds;
  726. {
  727.         FILE_HDR  fh;
  728.         BUFFER   buf;
  729.  
  730.         db_error = 0;
  731.  
  732.         db_check_ds(ds);
  733.         if (db_error) return(0);
  734.  
  735.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  736.         buf = ds->ds_buf;
  737.  
  738.         if (!buf->buf_cur_blk || !buf->buf_rec_inx)
  739.         {       db_error = DB_NO_CURRENT_REC;
  740.                 return(0);
  741.         }
  742.  
  743.         return((long)(buf->buf_cur_blk - 1) * fh->fh_recs_per_blk
  744.                                                          + buf->buf_rec_inx);
  745. }
  746.  
  747. /*
  748.  *      db_read_direct  -  Read a record by number
  749.  */                                               
  750.  
  751. void db_read_direct(ds, rec_no, user_data)
  752.  DATA_SET     ds;
  753.  ulong    rec_no;
  754.  char  *user_data;
  755. {
  756.         FILE_HDR    fh;
  757.         BUFFER      buf;
  758.         INDEX_HDR   ihdr;
  759.         RANDOM_HDR  rhdr;
  760.         RANDOM_REC  rrec;
  761.         SEQ_REC     seq;
  762.         ulong       blk;
  763.         ushort      rec;
  764.         char       *rbuf;
  765.  
  766.         db_error = 0;
  767.                                        
  768.         db_check_ds(ds);
  769.     if (db_error) return;
  770.  
  771.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  772.         buf = ds->ds_buf;
  773.  
  774.         buf->buf_cur_blk = 0;
  775.         buf->buf_rec_inx = 0;
  776.  
  777.         blk = rec_no / fh->fh_recs_per_blk;
  778.         rec = rec_no % fh->fh_recs_per_blk;
  779.  
  780.         if (rec == 0)
  781.                 rec = fh->fh_recs_per_blk;
  782.         else
  783.                 blk++;
  784.  
  785.         db_get_blk(ds, blk, buf);
  786.     if (db_error) return;
  787.  
  788.         switch (fh->fh_file_type)
  789.         {       case DB_SEQ:
  790.                         rbuf = buf->buf_data + (rec-1) * fh->fh_rec_size;
  791.                         seq  = (SEQ_REC) rbuf;
  792.                         
  793.                         if (seq->seq_stat != DB_INUSE)
  794.                         {       db_error = DB_DELETED_REC;
  795.                 return;
  796.                         }
  797.                         break;
  798.  
  799.                 case DB_INDEX:
  800.                         ihdr = (INDEX_HDR) buf->buf_data;
  801.                         
  802.                         if (ihdr->idx_stat != DB_INUSE)
  803.                         {       db_error = DB_DELETED_REC;
  804.                 return;
  805.                         }
  806.  
  807.                         if (rec > ihdr->idx_rec_cnt)
  808.                         {       db_error = DB_DELETED_REC;
  809.                 return;
  810.                         }
  811.  
  812.                         rbuf = buf->buf_data + sizeof(struct db_index_hdr)
  813.                                                 + (rec - 1) * fh->fh_rec_size;
  814.                         break;
  815.  
  816.                 case DB_RANDOM:
  817.                         rhdr = (RANDOM_HDR) buf->buf_data;
  818.                         
  819.                         if (rhdr->ran_stat != DB_INUSE)
  820.                         {       db_error = DB_DELETED_REC;
  821.                 return;
  822.                         }
  823.  
  824.                         if (rec > rhdr->ran_rec_cnt)
  825.                         {       db_error = DB_DELETED_REC;
  826.                 return;
  827.                         }
  828.  
  829.                         rbuf = buf->buf_data + sizeof(struct db_random_hdr)
  830.                                                 + (rec - 1) * fh->fh_rec_size;
  831.  
  832.                         rrec = (RANDOM_REC) rbuf;
  833.                         if (rrec->ran_stat != DB_INUSE)
  834.                         {       db_error = DB_DELETED_REC;
  835.                 return;
  836.                         }
  837.  
  838.                         break;
  839.  
  840.                 default:
  841.                         db_error = DB_INVALID_REQUEST;
  842.             return;
  843.         }
  844.         memcpy(user_data, rbuf + fh->fh_ctl_size, fh->fh_data_size);
  845.  
  846.         ds->ds_prev_blk = buf->buf_cur_blk = blk;
  847.         ds->ds_prev_rec = buf->buf_rec_inx = rec;
  848.  
  849.     return;
  850. }
  851.  
  852. /*
  853.  *      db_read_atr  - Read Data Set Attribute Block
  854.  */
  855.  
  856. void db_read_atr(ds, user_data)
  857.  DATA_SET ds;
  858.  char  *user_data;
  859. {        
  860.         FILE_HDR fh;
  861.  
  862.         db_error = 0;
  863.  
  864.         db_check_ds(ds);
  865.         if (db_error) return;
  866.  
  867.         fh = (FILE_HDR) ds->ds_fhdr->buf_data;
  868.  
  869.         memcpy(user_data, fh->fh_user_data, fh->fh_atr_size);
  870.  
  871.     return;
  872. }
  873.  
  874. /*
  875.  *      db_update_atr  - Update Data Set Attribute Block
  876.  */
  877.  
  878. void db_update_atr(ds, user_data)
  879.  DATA_SET ds;
  880.  char  *user_data;
  881. {
  882.         FILE_HDR fh;
  883.  
  884.         db_error = 0;
  885.  
  886.         db_check_ds(ds);
  887.         if (db_error) return;
  888.  
  889.         fh = (FILE_HDR) ds->ds_fhdr->buf_data;
  890.  
  891.         memcpy(fh->fh_user_data, user_data, fh->fh_atr_size);
  892.  
  893.         db_put_blk(ds, ds->ds_fhdr);
  894.  
  895.     return;
  896. }
  897.  
  898. /*
  899.  *      db_check_ds  -  Common checks on Data Set Validity
  900.  */                                                       
  901.  
  902. void db_check_ds(ds)
  903.  DATA_SET ds;
  904. {
  905.         FILE_HDR fh;
  906.  
  907.         db_error = 0;
  908.  
  909.         if (!ds)
  910.         {       db_error = DB_FILE_NOT_OPEN;
  911.                 return;
  912.         }
  913.  
  914.         if (!ds->ds_stat & DB_OPEN)
  915.         {       db_error = DB_FILE_NOT_OPEN;
  916.                 return;
  917.         }
  918.  
  919.         if (!ds->ds_fhdr || !ds->ds_buf)
  920.         {       db_error = DB_BUFFER_ERROR;
  921.                 return;
  922.         }
  923.  
  924.         fh = (FILE_HDR) ds->ds_fhdr->buf_data;
  925.  
  926.         if (fh->fh_file_type == DB_INDEX)
  927.                 if (!ds->ds_tmp || !ds->ds_aux)
  928.                 {       db_error = DB_BUFFER_ERROR;
  929.                         return;
  930.                 }
  931. }
  932.  
  933. /*
  934.  *      db_extend  -  Extend a data set by 1 Block
  935.  */
  936.  
  937. void db_extend(ds, buf)
  938.  DATA_SET ds;
  939.  BUFFER   buf;
  940. {
  941.         FILE_HDR  fhdr;
  942.         long       rec;
  943.         char        *c;
  944.         FREE_REC   fre;
  945.         RANDOM_HDR ran;
  946.         SEQ_REC    seq;
  947.         int        cnt;
  948.  
  949.  
  950.         fhdr                = (FILE_HDR) ds->ds_fhdr->buf_data;
  951.         buf                 = ds->ds_buf;
  952.         fhdr->fh_last_block = fhdr->fh_last_block + 1;
  953.         buf->buf_cur_blk    = fhdr->fh_last_block;
  954.         buf->buf_cur_size   = fhdr->fh_block_size;
  955.  
  956.         memset(buf->buf_data, 0, buf->buf_cur_size);
  957.  
  958.         switch(fhdr->fh_file_type)
  959.         {       case DB_SEQ:     
  960.                         rec = buf->buf_cur_blk * fhdr->fh_recs_per_blk;
  961.                         c   = buf->buf_data + (fhdr->fh_recs_per_blk - 1)
  962.                                                         * fhdr->fh_rec_size;
  963.  
  964.                         for (cnt=0; cnt < fhdr->fh_recs_per_blk; cnt++)
  965.                         {       fre                 = (FREE_REC) c;
  966.                                 fre->fre_stat       = DB_FREE;
  967.                                 fre->fre_next       = fhdr->fh_next_avail;
  968.                                 fhdr->fh_next_avail = rec--;
  969.                                 c                  -= fhdr->fh_rec_size;
  970.                         }
  971.                         break;
  972.  
  973.                 case DB_RANDOM:
  974.                         c = buf->buf_data + sizeof(struct db_random_hdr);
  975.                         for (cnt=0; cnt < fhdr->fh_recs_per_blk; cnt++)
  976.                         {       *c  = DB_FREE;
  977.                                  c += fhdr->fh_rec_size;
  978.                         }
  979.                         if (buf->buf_cur_blk <= fhdr->fh_base_size)
  980.                         {       ran = (RANDOM_HDR) buf->buf_data;
  981.                                 ran->ran_stat    = DB_INUSE;
  982.                                 ran->ran_next    = 0;
  983.                                 ran->ran_rec_cnt = 0;
  984.                         }
  985.                         else
  986.                         {       fre = (FREE_REC) buf->buf_data;
  987.                                 fre->fre_stat = DB_FREE;
  988.                                 fre->fre_next = fhdr->fh_next_avail;
  989.                                 fhdr->fh_next_avail = buf->buf_cur_blk;
  990.                         }
  991.                         break;
  992.  
  993.                 case DB_INDEX:
  994.                         fre = (FREE_REC) buf->buf_data;
  995.                         fre->fre_stat = DB_FREE;               
  996.                         fre->fre_next = fhdr->fh_next_avail;
  997.                         fhdr->fh_next_avail = buf->buf_cur_blk;
  998.                         break;
  999.         }
  1000.  
  1001.         db_put_blk(ds,ds->ds_buf);
  1002.         db_put_blk(ds,ds->ds_fhdr);
  1003. }
  1004.  
  1005. /*
  1006.  *      db_get_next_avail  -  Get Next Available Block
  1007.  */
  1008.  
  1009. void db_get_next_avail(ds, buf)
  1010.  DATA_SET ds;
  1011.  BUFFER  buf;
  1012. {
  1013.         FILE_HDR     fh;
  1014.         FREE_REC    fre;
  1015.         RANDOM_HDR rhdr;
  1016.         INDEX_HDR  ihdr;
  1017.         ulong       blk;
  1018.         ushort      rec;
  1019.         char      *rbuf;
  1020.  
  1021.         db_error = 0;
  1022.  
  1023.         fh  = (FILE_HDR) ds->ds_fhdr->buf_data;
  1024.  
  1025.         if (!fh->fh_next_avail)
  1026.         {       db_extend(ds, buf);
  1027.                 if (db_error) return;
  1028.         }
  1029.  
  1030.         if (fh->fh_file_type == DB_SEQ)
  1031.         {       blk = fh->fh_next_avail / fh->fh_recs_per_blk;
  1032.                 rec = fh->fh_next_avail % fh->fh_recs_per_blk;
  1033.  
  1034.                 if (rec==0)
  1035.                         rec = fh->fh_recs_per_blk;
  1036.                 else
  1037.                         blk++;
  1038.         }
  1039.         else
  1040.         {       blk = fh->fh_next_avail;
  1041.                 rec = 1;
  1042.         }
  1043.  
  1044.         db_get_blk(ds, blk, buf);
  1045.         if (db_error) return;
  1046.  
  1047.         buf->buf_rec_inx = rec;
  1048.         rbuf = buf->buf_data + (rec - 1) * fh->fh_rec_size;
  1049.  
  1050.         fre = (FREE_REC) rbuf;
  1051.         if (fre->fre_stat != DB_FREE)
  1052.         {       db_error = DB_INVALID_FREE;
  1053.                 return;
  1054.         }
  1055.  
  1056.         fre->fre_stat     = DB_INUSE;
  1057.         fh->fh_next_avail = fre->fre_next;
  1058.  
  1059.         if (fh->fh_file_type == DB_INDEX)
  1060.                 if (!fh->fh_root_ptr)
  1061.                         fh->fh_root_ptr = blk;
  1062.  
  1063.         switch (fh->fh_file_type)
  1064.         {       case DB_SEQ:
  1065.                         break;
  1066.  
  1067.                 case DB_RANDOM:
  1068.                         rhdr = (RANDOM_HDR) rbuf;
  1069.                         rhdr->ran_next = 0;
  1070.                         rhdr->ran_rec_cnt = 0;
  1071.                         break;
  1072.  
  1073.                 case DB_INDEX:
  1074.                         ihdr = (INDEX_HDR) rbuf;
  1075.                         ihdr->idx_parent = 0;
  1076.                         ihdr->idx_rec_cnt = 0;
  1077.                         break;
  1078.         }
  1079. }
  1080.  
  1081. /*
  1082.  *      db_free_rec  -  Free a deleted record
  1083.  */
  1084.  
  1085. void db_free_rec(ds, buf)
  1086.  DATA_SET ds;
  1087.  BUFFER   buf;
  1088. {
  1089.         FILE_HDR  fh;
  1090.         FREE_REC fre;
  1091.  
  1092.         db_error = 0;
  1093.  
  1094.         fh = (FILE_HDR) ds->ds_fhdr->buf_data;
  1095.  
  1096.         switch (fh->fh_file_type)
  1097.         {       case DB_SEQ:
  1098.                         fre = (FREE_REC) (buf->buf_data 
  1099.                                 + (buf->buf_rec_inx - 1) * fh->fh_rec_size);
  1100.                         memset(fre, 0, fh->fh_rec_size);
  1101.                         fre->fre_stat     = DB_FREE;
  1102.                         fre->fre_next     = fh->fh_next_avail;
  1103.                         fh->fh_next_avail = (long) (buf->buf_cur_blk - 1)
  1104.                                   * fh->fh_recs_per_blk + buf->buf_rec_inx;
  1105.                         break;
  1106.  
  1107.                 case DB_RANDOM:
  1108.                         fre = (FREE_REC) buf->buf_data;
  1109.                         fre->fre_stat     = DB_FREE;
  1110.                         fre->fre_next     = fh->fh_next_avail;
  1111.                         fh->fh_next_avail = buf->buf_cur_blk;
  1112.                         break;                               
  1113.  
  1114.                 case DB_INDEX:
  1115.                         fre = (FREE_REC) buf->buf_data;
  1116.                         memset(fre, 0, fh->fh_block_size);
  1117.                         fre->fre_stat     = DB_FREE;
  1118.                         fre->fre_next     = fh->fh_next_avail;
  1119.                         fh->fh_next_avail = buf->buf_cur_blk;
  1120.                         break;                               
  1121.         }
  1122.         db_put_blk(ds, buf);
  1123.         if (db_error) return;
  1124. }
  1125.  
  1126. /*
  1127.  *      db_get_blk  -  Get a Block from a Data Set
  1128.  */
  1129.  
  1130. void db_get_blk(ds,blk,buf)
  1131.  DATA_SET ds;         
  1132.  long     blk;
  1133.  BUFFER   buf;
  1134. {
  1135.         FILE_HDR  fhdr;
  1136.         long psn, lseek();
  1137.         int cnt;          
  1138.                                 
  1139.         db_error = 0;
  1140.  
  1141.         if (!ds)
  1142.         {       db_error = DB_FILE_NOT_OPEN;
  1143.                 return;
  1144.         }
  1145.  
  1146.         if (!ds->ds_stat & DB_OPEN)
  1147.         {       db_error = DB_FILE_NOT_OPEN;
  1148.                 return;
  1149.         }
  1150.         
  1151.         if (!buf)
  1152.         {       db_error = DB_BUFFER_ERROR;
  1153.                 return;
  1154.         }
  1155.  
  1156.         fhdr = (FILE_HDR) ds->ds_fhdr->buf_data;
  1157.                       
  1158.         if (blk == 0)
  1159.                 psn = 0;
  1160.         else
  1161.                 psn = sizeof(struct db_file_hdr) 
  1162.                     + (blk-1) * fhdr->fh_block_size;
  1163.  
  1164.         buf->buf_cur_blk  = 0;
  1165.         buf->buf_cur_size = 0;
  1166.  
  1167.         if (lseek(ds->ds_fd, psn, 0) < 0)
  1168.         {       db_error = DB_INVALID_BLOCK;
  1169.                 return;
  1170.         }
  1171.  
  1172.         cnt = read(ds->ds_fd, buf->buf_data, buf->buf_size);
  1173.         if (cnt < 0)
  1174.         {       db_error = DB_READ_ERROR;
  1175.                 return;
  1176.         }
  1177.  
  1178.         if (cnt == 0)
  1179.         {       db_error = DB_END_OF_FILE;
  1180.                 return;
  1181.         }            
  1182.  
  1183.         buf->buf_cur_blk  = blk;
  1184.         buf->buf_cur_size = cnt;
  1185. }
  1186.  
  1187. /*
  1188.  *      db_put_blk  -  Put a Block out to a Data Set
  1189.  */
  1190.  
  1191. void db_put_blk(ds,buf)
  1192.  DATA_SET ds;         
  1193.  BUFFER   buf;
  1194. {
  1195.         FILE_HDR  fhdr;
  1196.         long psn, lseek();
  1197.         int cnt;          
  1198.                                 
  1199.         db_error = 0;
  1200.  
  1201.         if (!ds)
  1202.         {       db_error = DB_FILE_NOT_OPEN;
  1203.                 return;
  1204.         }
  1205.  
  1206.         if (!ds->ds_stat & DB_OPEN)
  1207.         {       db_error = DB_FILE_NOT_OPEN;
  1208.                 return;
  1209.         }
  1210.         
  1211.         if (!buf)
  1212.         {       db_error = DB_BUFFER_ERROR;
  1213.                 return;
  1214.         }
  1215.  
  1216.         if (buf->buf_cur_size == 0)
  1217.         {       db_error = DB_INVALID_BLK_SIZE;
  1218.                 return;
  1219.         }
  1220.  
  1221.         fhdr = (FILE_HDR) ds->ds_fhdr->buf_data;
  1222.  
  1223.         if (buf->buf_cur_blk == 0)
  1224.                 psn = 0;
  1225.         else
  1226.                 psn  = sizeof(struct db_file_hdr)
  1227.                      + (buf->buf_cur_blk - 1) * fhdr->fh_block_size;
  1228.  
  1229.         if (lseek(ds->ds_fd, psn, 0) < 0)
  1230.         {       db_error = DB_INVALID_BLOCK;
  1231.                 return;
  1232.         }
  1233.  
  1234.         cnt = write(ds->ds_fd, buf->buf_data, buf->buf_cur_size);
  1235.         if (cnt != buf->buf_cur_size)
  1236.         {       db_error = DB_WRITE_ERROR;
  1237.                 return;
  1238.         }
  1239. }
  1240.  
  1241. /*
  1242.  *      db_alloc_buf  -  Get a Buffer
  1243.  */
  1244.  
  1245. BUFFER db_alloc_buf(size)
  1246.  int size;
  1247. {
  1248.         BUFFER  buf;
  1249.         char   *calloc();
  1250.  
  1251.         buf = (BUFFER) calloc(1, sizeof(struct db_data_buf));
  1252.  
  1253.         if (size)
  1254.         {       buf->buf_size  = size;
  1255.                 buf->buf_data  = (char *) calloc(1, size);
  1256.         }
  1257.  
  1258.         return(buf);
  1259. }
  1260.  
  1261.  
  1262.  
  1263. /*
  1264.  *      db_free_buf  -  Free a Buffer
  1265.  */
  1266.  
  1267. BUFFER db_free_buf(buf)
  1268.  BUFFER buf;
  1269. {      
  1270.         BUFFER prev,next;
  1271.  
  1272.     if (!buf) return(NULL);
  1273.  
  1274.     if (!buf->buf_data) return(NULL);
  1275.                     
  1276.         prev = buf->buf_prev;
  1277.         next = buf->buf_next;
  1278.  
  1279.         if (prev) prev->buf_next = buf->buf_next;
  1280.  
  1281.         if (next) next->buf_prev = buf->buf_prev;
  1282.  
  1283.         free(buf->buf_data);
  1284.         free(buf);
  1285.         
  1286.         return(next);
  1287. }
  1288.  
  1289. /*
  1290.  *      db_free_ds  -  Free all dynamic structures for a Data Set
  1291.  */
  1292.  
  1293. void db_free_ds(ds)
  1294.  DATA_SET ds;
  1295. {
  1296.         if (!ds) return;
  1297.  
  1298.         if (ds->ds_fhdr)
  1299.                 db_free_buf(ds->ds_fhdr);
  1300.  
  1301.         while (ds->ds_buf)
  1302.                 ds->ds_buf = db_free_buf(ds->ds_buf);
  1303.  
  1304.         if (ds->ds_tmp)
  1305.                 db_free_buf(ds->ds_tmp);
  1306.  
  1307.         if (ds->ds_aux)
  1308.                 db_free_buf(ds->ds_aux);
  1309.  
  1310.     return;
  1311. }
  1312.  
  1313. /*
  1314.  *      db_error_msg  -  Return pointer to error message text
  1315.  */
  1316.  
  1317. static char *db_error_msgs[] =
  1318. {"",
  1319.  "DB-Data Set Not Found",    /*  1 */
  1320.  "DB-Read Error",            /*  2 */
  1321.  "DB-End Of File",           /*  3 */
  1322.  "DB-Write Error",           /*  4 */
  1323.  "DB-Data Set Not Created",  /*  5 */
  1324.  "DB-Data Set Not Open",     /*  6 */
  1325.  "DB-Invalid Block",         /*  7 */
  1326.  "DB-Buffer Error",          /*  8 */
  1327.  "DB-No Current Record",     /*  9 */
  1328.  "DB-Record Deleted",        /* 10 */
  1329.  "DB-Free List Error",       /* 11 */
  1330.  "DB-Invalid Block Size",    /* 12 */
  1331.  "DB-Index File Corrupted",  /* 13 */
  1332.  "DB-Record Not Found",      /* 14 */
  1333.  "DB-Duplicate Key",         /* 15 */
  1334.  "DB-Invalid Request",       /* 16 */
  1335.  "DB-Random File Corrupted", /* 17 */
  1336.  "DB-Invalid File Header",   /* 18 */
  1337.  "DB-File Version Mismatch", /* 19 */
  1338.  ""};
  1339.  
  1340. char *db_error_msg(error)
  1341.  int error;
  1342. {
  1343.         return(db_error_msgs[error]);
  1344. }
  1345.  
  1346. /*
  1347.  *        memcpy - copy a block of memory taking care not to overlap
  1348.  */
  1349.  
  1350. memcpy(dst, src, cnt)
  1351.  char *dst, *src;
  1352.  int   cnt;
  1353. {
  1354.     char *s, *d;
  1355.  
  1356.     if (dst > src  &&  dst < src+cnt)
  1357.     {    s = src + cnt - 1;
  1358.         d = dst + cnt - 1;
  1359.         while (cnt--) *d-- = *s--;
  1360.     }
  1361.     else
  1362.         while (cnt--) *dst++ = *src++;
  1363. }
  1364.                  
  1365.