home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progc / itcoct90.arj / DBWRITE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-07  |  8.3 KB  |  277 lines

  1. /****************************************************************
  2. * DBWRITE.C - routines to handle writing to dBASE III/IV files    *
  3. * 900911 MCMason - Turbo C v2.01, Turbo C++ v1.00                *
  4. * To compile, type: "tcc dbwrite"                                *
  5. ****************************************************************/
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <dos.h>
  11. #include <io.h>
  12. #include "dbase.h"
  13.  
  14. /*----- Handy macros -----*/
  15. #define Day_upd update[2]                /* Day of last update    */
  16. #define Mon_upd update[1]                /* Month of last update    */
  17. #define Yr_upd  update[0]                /* Year of last update    */
  18. #define F(x) (*x->fld)                    /* Field access            */
  19.  
  20. /*----- dBASE file descriptor -----*/
  21. struct _dbfHdrMask
  22.     {
  23.     char    Version;        /* Version of file type                */
  24.     char    update[3];        /* The last date file was changed    */
  25.     long    NumRex;            /* Number of records in dBASE file    */
  26.     int        HdrLen;            /* Size of dBASE header                */
  27.     int        RecLen;            /* Size of a single record            */
  28.     char    Reserved[20];    /* Pad structure to 32 bytes        */
  29.     };
  30.  
  31. /*----- dBASE field descriptor -----*/
  32. struct _dbfFldMask
  33.     {
  34.     char    Name[11];        /* Name of the field                */
  35.     char    Type;            /* Field type (C, D, F, L, M, N)    */
  36.     char    Reserved1[4];    /* Move Length to sixteenth byte    */
  37.     unsigned char Length;    /* Length of record                    */
  38.     unsigned char Dec;        /* Number of decimal positions        */
  39.     char    Reserved2[14];    /* Pad structure to 32 bytes        */
  40.     };
  41.  
  42. /****************************************************************
  43. * dbfOpen - open a dBASE III+/IV data file for read & write.    *
  44. *                                                                *
  45. * INP:    fname - file name                                        *
  46. * OUT:    dbfFILE pointer, or NULL if error.                        *
  47. ****************************************************************/
  48. dbfFILE dbfOpen(const char *fname)
  49.     {
  50.     int i;
  51.     dbfFILE r;
  52.     struct _dbfHdrMask h;
  53.     struct _dbfFldMask FldTmp;
  54.  
  55.     /* Allocate dBASE file data block */
  56.     r=(dbfFILE)malloc(sizeof(struct _dbfFILE));
  57.     if (r==NULL)
  58.         return NULL;
  59.  
  60.     /* Open the file */
  61.     r->file = fopen(fname,"r+b");
  62.     if (r->file==NULL)
  63.         goto dbfOpenErrorExit;
  64.  
  65.     /* Read the dBASE header data */
  66.     if (fread(&h,sizeof(h),1,r->file) != 1)
  67.         goto dbfOpenErrorExit2;
  68.     r->Version = h.Version & 0x07;
  69.     r->Day_upd = h.Day_upd;
  70.     r->Mon_upd = h.Mon_upd;
  71.     r->Yr_upd  = h.Yr_upd;
  72.     r->NumRex  = h.NumRex;
  73.     r->HdrLen  = h.HdrLen;
  74.     r->RecLen  = h.RecLen;
  75.     r->NumFlds = (h.HdrLen - 33)/32;
  76.     r->FileSize= h.HdrLen+h.RecLen*h.NumRex+1;
  77.     r->Modified= FALSE;
  78.     if (r->Version != 3)
  79.         goto dbfOpenErrorExit2;
  80.  
  81.     /* Allocate the RAM block, now that we know    */
  82.     /* how much room we need ...                */
  83.     r->fld = malloc(sizeof(struct _dbfFLD)*r->NumFlds);
  84.     if (r->fld == NULL)
  85.         goto dbfOpenErrorExit2;
  86.  
  87.     /* Read in all the field descriptors */
  88.     for (i=0; i<r->NumFlds; i++)
  89.         {
  90.         if ( fread(&FldTmp,sizeof(FldTmp),1,r->file) != 1 )
  91.             goto dbfOpenErrorExit3;
  92.         strncpy(F(r)[i].Name,FldTmp.Name,11);
  93.         F(r)[i].Type   = FldTmp.Type;
  94.         F(r)[i].Length = FldTmp.Length;
  95.         F(r)[i].Dec    = FldTmp.Dec;
  96.         }
  97.  
  98.     /* Done ... return pointer to data */
  99.     return r;
  100.  
  101.     /*******************************************
  102.     * Only get here when an error has occurred *
  103.     *******************************************/
  104. dbfOpenErrorExit3:        /* Fields & header allocated, file open */
  105.     free(r->fld);
  106. dbfOpenErrorExit2:        /*--- Header allocated & file is open --*/
  107.     fclose(r->file);
  108. dbfOpenErrorExit:        /*-------- Header allocated only -------*/
  109.     free((void *)r);
  110.     return NULL;        /* Return error code    */
  111.     }
  112.  
  113. /************************************************************
  114. * dbfClose - close the dBase file specified by 'hdr'        *
  115. *                                                            *
  116. * INP:    hdr - a standard dBase file header                    *
  117. * OUT:    TRUE on error                                        *
  118. ************************************************************/
  119. int dbfClose(dbfFILE hdr)
  120.     {
  121.     int retval;
  122.     struct _dbfHdrMask h;
  123.  
  124.     /* Assume error status, unless we get through all steps    */
  125.     retval = TRUE;
  126.  
  127.     if (hdr->Modified)
  128.         {
  129.         /* Read the dBASE header data */
  130.         if (fseek(hdr->file,0L,SEEK_SET))
  131.             goto dbfCloseError;
  132.         if (fread(&h,sizeof(h),1,hdr->file) != 1)
  133.             goto dbfCloseError;
  134.  
  135.         /* Update the dBASE header data fields */
  136.         h.Day_upd = hdr->Day_upd;
  137.         h.Mon_upd = hdr->Mon_upd;
  138.         h.Yr_upd  = hdr->Yr_upd;
  139.         h.NumRex  = hdr->NumRex;
  140.  
  141.         /* Rewrite the dBASE header data */
  142.         if (fseek(hdr->file,0L,SEEK_SET))
  143.             goto dbfCloseError;
  144.         if (fwrite(&h,sizeof(h),1,hdr->file) != 1)
  145.             goto dbfCloseError;
  146.         }
  147.  
  148.     /* Everything went well ... */
  149.     retval = FALSE;
  150.  
  151.     /* Perform last little bit of cleanup */
  152. dbfCloseError:
  153.     if (fclose(hdr->file))
  154.         return TRUE;        /* One last chance for failure        */
  155.     free(hdr->fld);            /* Free the field descriptor list    */
  156.     free(hdr);                /* Free the dBASE file descriptor    */
  157.     return retval;
  158.     }
  159.  
  160. /****************************************************************
  161. * dbfReadRec - Read a dBASE record to the specified buffer        *
  162. *                                                                *
  163. * INP:    hdr - handle to the dBASE file                            *
  164. *        Rec - the record number to write                        *
  165. *        b   - pointer to the buffer holding the record to write    *
  166. * OUT:    TRUE on error, FALSE otherwise                            *
  167. ****************************************************************/
  168. int dbfReadRec(dbfFILE hdr, long Rec, char *b)
  169.     {
  170.     long CurrentPos;
  171.  
  172.     CurrentPos=(Rec-1)*hdr->RecLen+hdr->HdrLen;
  173.     fseek(hdr->file,CurrentPos,SEEK_SET);
  174.     if (fread(b,hdr->RecLen,1,hdr->file) != 1)
  175.         return TRUE;
  176.     return FALSE;
  177.     }
  178.  
  179. /****************************************************************
  180. * dbfWriteRec - write a record to the dBASE file                *
  181. *                                                                *
  182. * INP:    hdr - handle to the dBASE file                            *
  183. *        Rec - the record number to write                        *
  184. *        b   - pointer to the buffer holding the record to write    *
  185. * OUT:    TRUE on error, FALSE otherwise                            *
  186. ****************************************************************/
  187. int dbfWriteRec(dbfFILE hdr, long Rec, char *b)
  188.     {
  189.     long CurrentPos;
  190.  
  191.     CurrentPos=(Rec-1)*hdr->RecLen+hdr->HdrLen;
  192.     fseek(hdr->file,CurrentPos,SEEK_SET);
  193.     if (fwrite(b,hdr->RecLen,1,hdr->file) != 1)
  194.         return TRUE;
  195.     hdr->Modified = TRUE;
  196.     return FALSE;
  197.     }
  198.  
  199. /****************************************************************
  200. * dbfAllocRec - allocate a new record in the dBASE file            *
  201. *                                                                *
  202. * INP:    hdr - handle to the dBASE file                            *
  203. * OUT:    the record number (positive)                            *
  204. ****************************************************************/
  205. long dbfAllocRec(dbfFILE hdr)
  206.     {
  207.     long RecStart;
  208.     int  i;
  209.  
  210.     /* Position file pointer to start of record, and write a    */
  211.     /* blank record and an end of data marker to the dBASE file    */
  212.     RecStart=hdr->NumRex*hdr->RecLen+hdr->HdrLen;
  213.     fseek(hdr->file,RecStart,SEEK_SET);
  214.     for (i=0; i<hdr->RecLen; i++)
  215.         fputc(' ',hdr->file);        /* spaces for blank record    */
  216.     fputc(0x1a,hdr->file);            /* End of DATA marker        */
  217.     hdr->Modified = TRUE;
  218.     return ++(hdr->NumRex);            /* Return new record number    */
  219.     }
  220.  
  221. /****************************************************************
  222. * main - the test routine for writing to dBASE files            *
  223. ****************************************************************/
  224. #define BUFFLEN        255        /* Size of scratch buffer            */
  225. void main(void)
  226.     {
  227.     dbfFILE  inDBF, outDBF;
  228.     char     buffer[BUFFLEN+1];
  229.     long     i,j;
  230.  
  231.     /* Open PLANETS.DBF as the input file */
  232.     inDBF = dbfOpen("PLANETS.DBF");
  233.     if (inDBF == NULL)
  234.         {
  235.         puts("ERROR - can't open the planets database!");
  236.         exit(1);
  237.         }
  238.  
  239.     /* Open NEWPLAN.DBF as the output file */
  240.     outDBF = dbfOpen("NEWPLAN.DBF");
  241.     if (outDBF == NULL)
  242.         {
  243.         puts("ERROR - can't open the new planets database!");
  244.         exit(1);
  245.         }
  246.  
  247.     /* Copy the planets from PLANETS to NEWPLAN, deleting every    */
  248.     /* other one, and activating the rest.                        */
  249.     memset(buffer,0,BUFFLEN);
  250.     for (i=1; i<=inDBF->NumRex; i++)
  251.         {
  252.         if (dbfReadRec(inDBF,(long)i,buffer))
  253.             {
  254.             printf("ERROR: can't read record #%d\n",i);
  255.             memset(buffer,' ',BUFFLEN);
  256.             }
  257.  
  258.         printf("Record %ld=\"%s\"\n",i,buffer);
  259.  
  260.         if (i&1) buffer[0]=' ';        /* Activate odd records        */
  261.         else     buffer[0]='*';        /* Delete even records        */
  262.  
  263.         j=dbfAllocRec(outDBF);
  264.         if (j<0)
  265.             printf("ERROR: can't allocate output record\n");
  266.         else
  267.             if (dbfWriteRec(outDBF,(long)j,buffer))
  268.                 printf("ERROR: can't write record #%d\n",j);
  269.         }
  270.  
  271.     /* Close the dBASE files */
  272.     if (dbfClose(inDBF))
  273.         puts("ERROR: trying to close PLANETS.DBF");
  274.     if (dbfClose(outDBF))
  275.         puts("ERROR: trying to close NEWPLAN.DBF");
  276.     }
  277.