home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- * DBWRITE.C - routines to handle writing to dBASE III/IV files *
- * 900911 MCMason - Turbo C v2.01, Turbo C++ v1.00 *
- * To compile, type: "tcc dbwrite" *
- ****************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dos.h>
- #include <io.h>
- #include "dbase.h"
-
- /*----- Handy macros -----*/
- #define Day_upd update[2] /* Day of last update */
- #define Mon_upd update[1] /* Month of last update */
- #define Yr_upd update[0] /* Year of last update */
- #define F(x) (*x->fld) /* Field access */
-
- /*----- dBASE file descriptor -----*/
- struct _dbfHdrMask
- {
- char Version; /* Version of file type */
- char update[3]; /* The last date file was changed */
- long NumRex; /* Number of records in dBASE file */
- int HdrLen; /* Size of dBASE header */
- int RecLen; /* Size of a single record */
- char Reserved[20]; /* Pad structure to 32 bytes */
- };
-
- /*----- dBASE field descriptor -----*/
- struct _dbfFldMask
- {
- char Name[11]; /* Name of the field */
- char Type; /* Field type (C, D, F, L, M, N) */
- char Reserved1[4]; /* Move Length to sixteenth byte */
- unsigned char Length; /* Length of record */
- unsigned char Dec; /* Number of decimal positions */
- char Reserved2[14]; /* Pad structure to 32 bytes */
- };
-
- /****************************************************************
- * dbfOpen - open a dBASE III+/IV data file for read & write. *
- * *
- * INP: fname - file name *
- * OUT: dbfFILE pointer, or NULL if error. *
- ****************************************************************/
- dbfFILE dbfOpen(const char *fname)
- {
- int i;
- dbfFILE r;
- struct _dbfHdrMask h;
- struct _dbfFldMask FldTmp;
-
- /* Allocate dBASE file data block */
- r=(dbfFILE)malloc(sizeof(struct _dbfFILE));
- if (r==NULL)
- return NULL;
-
- /* Open the file */
- r->file = fopen(fname,"r+b");
- if (r->file==NULL)
- goto dbfOpenErrorExit;
-
- /* Read the dBASE header data */
- if (fread(&h,sizeof(h),1,r->file) != 1)
- goto dbfOpenErrorExit2;
- r->Version = h.Version & 0x07;
- r->Day_upd = h.Day_upd;
- r->Mon_upd = h.Mon_upd;
- r->Yr_upd = h.Yr_upd;
- r->NumRex = h.NumRex;
- r->HdrLen = h.HdrLen;
- r->RecLen = h.RecLen;
- r->NumFlds = (h.HdrLen - 33)/32;
- r->FileSize= h.HdrLen+h.RecLen*h.NumRex+1;
- r->Modified= FALSE;
- if (r->Version != 3)
- goto dbfOpenErrorExit2;
-
- /* Allocate the RAM block, now that we know */
- /* how much room we need ... */
- r->fld = malloc(sizeof(struct _dbfFLD)*r->NumFlds);
- if (r->fld == NULL)
- goto dbfOpenErrorExit2;
-
- /* Read in all the field descriptors */
- for (i=0; i<r->NumFlds; i++)
- {
- if ( fread(&FldTmp,sizeof(FldTmp),1,r->file) != 1 )
- goto dbfOpenErrorExit3;
- strncpy(F(r)[i].Name,FldTmp.Name,11);
- F(r)[i].Type = FldTmp.Type;
- F(r)[i].Length = FldTmp.Length;
- F(r)[i].Dec = FldTmp.Dec;
- }
-
- /* Done ... return pointer to data */
- return r;
-
- /*******************************************
- * Only get here when an error has occurred *
- *******************************************/
- dbfOpenErrorExit3: /* Fields & header allocated, file open */
- free(r->fld);
- dbfOpenErrorExit2: /*--- Header allocated & file is open --*/
- fclose(r->file);
- dbfOpenErrorExit: /*-------- Header allocated only -------*/
- free((void *)r);
- return NULL; /* Return error code */
- }
-
- /************************************************************
- * dbfClose - close the dBase file specified by 'hdr' *
- * *
- * INP: hdr - a standard dBase file header *
- * OUT: TRUE on error *
- ************************************************************/
- int dbfClose(dbfFILE hdr)
- {
- int retval;
- struct _dbfHdrMask h;
-
- /* Assume error status, unless we get through all steps */
- retval = TRUE;
-
- if (hdr->Modified)
- {
- /* Read the dBASE header data */
- if (fseek(hdr->file,0L,SEEK_SET))
- goto dbfCloseError;
- if (fread(&h,sizeof(h),1,hdr->file) != 1)
- goto dbfCloseError;
-
- /* Update the dBASE header data fields */
- h.Day_upd = hdr->Day_upd;
- h.Mon_upd = hdr->Mon_upd;
- h.Yr_upd = hdr->Yr_upd;
- h.NumRex = hdr->NumRex;
-
- /* Rewrite the dBASE header data */
- if (fseek(hdr->file,0L,SEEK_SET))
- goto dbfCloseError;
- if (fwrite(&h,sizeof(h),1,hdr->file) != 1)
- goto dbfCloseError;
- }
-
- /* Everything went well ... */
- retval = FALSE;
-
- /* Perform last little bit of cleanup */
- dbfCloseError:
- if (fclose(hdr->file))
- return TRUE; /* One last chance for failure */
- free(hdr->fld); /* Free the field descriptor list */
- free(hdr); /* Free the dBASE file descriptor */
- return retval;
- }
-
- /****************************************************************
- * dbfReadRec - Read a dBASE record to the specified buffer *
- * *
- * INP: hdr - handle to the dBASE file *
- * Rec - the record number to write *
- * b - pointer to the buffer holding the record to write *
- * OUT: TRUE on error, FALSE otherwise *
- ****************************************************************/
- int dbfReadRec(dbfFILE hdr, long Rec, char *b)
- {
- long CurrentPos;
-
- CurrentPos=(Rec-1)*hdr->RecLen+hdr->HdrLen;
- fseek(hdr->file,CurrentPos,SEEK_SET);
- if (fread(b,hdr->RecLen,1,hdr->file) != 1)
- return TRUE;
- return FALSE;
- }
-
- /****************************************************************
- * dbfWriteRec - write a record to the dBASE file *
- * *
- * INP: hdr - handle to the dBASE file *
- * Rec - the record number to write *
- * b - pointer to the buffer holding the record to write *
- * OUT: TRUE on error, FALSE otherwise *
- ****************************************************************/
- int dbfWriteRec(dbfFILE hdr, long Rec, char *b)
- {
- long CurrentPos;
-
- CurrentPos=(Rec-1)*hdr->RecLen+hdr->HdrLen;
- fseek(hdr->file,CurrentPos,SEEK_SET);
- if (fwrite(b,hdr->RecLen,1,hdr->file) != 1)
- return TRUE;
- hdr->Modified = TRUE;
- return FALSE;
- }
-
- /****************************************************************
- * dbfAllocRec - allocate a new record in the dBASE file *
- * *
- * INP: hdr - handle to the dBASE file *
- * OUT: the record number (positive) *
- ****************************************************************/
- long dbfAllocRec(dbfFILE hdr)
- {
- long RecStart;
- int i;
-
- /* Position file pointer to start of record, and write a */
- /* blank record and an end of data marker to the dBASE file */
- RecStart=hdr->NumRex*hdr->RecLen+hdr->HdrLen;
- fseek(hdr->file,RecStart,SEEK_SET);
- for (i=0; i<hdr->RecLen; i++)
- fputc(' ',hdr->file); /* spaces for blank record */
- fputc(0x1a,hdr->file); /* End of DATA marker */
- hdr->Modified = TRUE;
- return ++(hdr->NumRex); /* Return new record number */
- }
-
- /****************************************************************
- * main - the test routine for writing to dBASE files *
- ****************************************************************/
- #define BUFFLEN 255 /* Size of scratch buffer */
- void main(void)
- {
- dbfFILE inDBF, outDBF;
- char buffer[BUFFLEN+1];
- long i,j;
-
- /* Open PLANETS.DBF as the input file */
- inDBF = dbfOpen("PLANETS.DBF");
- if (inDBF == NULL)
- {
- puts("ERROR - can't open the planets database!");
- exit(1);
- }
-
- /* Open NEWPLAN.DBF as the output file */
- outDBF = dbfOpen("NEWPLAN.DBF");
- if (outDBF == NULL)
- {
- puts("ERROR - can't open the new planets database!");
- exit(1);
- }
-
- /* Copy the planets from PLANETS to NEWPLAN, deleting every */
- /* other one, and activating the rest. */
- memset(buffer,0,BUFFLEN);
- for (i=1; i<=inDBF->NumRex; i++)
- {
- if (dbfReadRec(inDBF,(long)i,buffer))
- {
- printf("ERROR: can't read record #%d\n",i);
- memset(buffer,' ',BUFFLEN);
- }
-
- printf("Record %ld=\"%s\"\n",i,buffer);
-
- if (i&1) buffer[0]=' '; /* Activate odd records */
- else buffer[0]='*'; /* Delete even records */
-
- j=dbfAllocRec(outDBF);
- if (j<0)
- printf("ERROR: can't allocate output record\n");
- else
- if (dbfWriteRec(outDBF,(long)j,buffer))
- printf("ERROR: can't write record #%d\n",j);
- }
-
- /* Close the dBASE files */
- if (dbfClose(inDBF))
- puts("ERROR: trying to close PLANETS.DBF");
- if (dbfClose(outDBF))
- puts("ERROR: trying to close NEWPLAN.DBF");
- }