#ident "$URL: svn://elmer/devel/SVN/SDDAS/trunk/libdB/OpenDbf.c $ %D% SwRI" #include #include #include #include #include #include #include #include #include "dbf.h" /******************* ** >FILE: OpenDbf.c *******************/ #define usc unsigned char /*********************************** ** Function: long MakeLong(char *r) ** ** Description: ** Decode a 4 byte number ** ** Return Values: ** a long value from a character pointer ** ***************** *****************/ SDDAS_LONG MakeLong(char *r) { return((((usc)r[0])*1) + (((usc)r[1]) * 256) + (((usc)r[2]) * 65536) + ((usc)r[3] * 16777216)); } /********************************** ** Function: int MakeInt(char *b) ** ** Description: ** Decode a 2 byte number ** ** Return Values: ** a int value from a character pointer ** ***************** *****************/ int MakeInt(char *b) { return((((usc)b[0]) * 1) + (((usc)b[1]) * 256)); } /***************************************************** ** Function: int GetOneFieldDesc(dbfRecord_t *D, ** FieldDesc_t *F, ** FieldRecord_t *Field, ** int *Offset) ** ** Description: ** Decode one field from the header ** ** Return Values: ** * FAILURE - dbf_code set to actual error ** * SUCCESS - the routine completed without error ** ***************** *****************/ dbRet_t GetOneFieldDesc(dbfRecord_t *D, FieldDesc_t *F, FieldRecord_t *Field, int *Offset) { int i; /* | initialize the field's name */ memset(Field->Name, 0, sizeof(Field->Name)); /* | get the name of the field */ for (i=0; *(*F+i) != 0 && i <= 10; i++) { Field->Name[i] = *(*F+i); } /* | the type of the field: Characer, Numeric, Date, Memo, or Logical */ Field->Typ = (char) *(*F+11); /* | decode the length of the field in bytes and get the # of decimals for this | field */ Field->Len = *(*F+16); Field->Dec = *(*F+17); /* | generate a pointer to the field in the current record */ Field->Parm = (char *)&(D->CurRecord[0][*Offset]); /* | increment the offset to the next field description */ *Offset += Field->Len; /* | make sure this field is valid */ if (!(Field->Typ == CHARACTER || Field->Typ == NUMERIC || Field->Typ == MEMO || Field->Typ == DATE || Field->Typ == LOGICAL)) { dbf_msg_clr; dbf_code = UNKNOWN_FIELD_TYPE; return FAILURE; } return SUCCESS; } /************************************************** ** Function: int ProcessHeader(dbfRecord_t *D, ** Header_t Header, ** int NumBytes) ** ** Description: ** Decode the header ** ** Return Values: ** * FAILURE - dbf_code set to actual error ** * SUCCESS - the routine completed without error ** ***************** *****************/ int ProcessHeader(dbfRecord_t *D, Header_t Header, int NumBytes) { int i, o, rval; unsigned int nbytes; FieldArray_t tempFields; /* | determine file type, must be a DBase III file */ switch(Header[0]) { case DB2File: (void)fprintf(stderr, "File Type: Dbase II\n"); dbf_code = NOT_DB_FILE; sprintf(msg, "'%s'", D->FileName); return FAILURE; break; case DB3File: break; case DB3WithMemo: (void)fprintf(stderr, "File Type: Dbase III w/memo\n"); dbf_code = NOT_DB_FILE; sprintf(msg, "'%s'", D->FileName); return FAILURE; break; default: (void)fprintf(stderr, "File Type: UNKNOWN\n"); sprintf(msg, "'%s'", D->FileName); dbf_code = NOT_DB_FILE; return FAILURE; break; } /* | decode the data of the last update to the database file */ (void)sprintf(D->DateOfUpdate, "%2d/%02d/%02d", Header[2], Header[3], Header[1]); /* | number of records in the database file */ D->NumRecs = MakeLong(&Header[4]); /* | get the size of the header */ D->HeadLen = MakeInt(&Header[8]); if (NumBytes < D->HeadLen) { (void)fprintf(stderr, "Not A Dbase File\n"); sprintf(msg, "'%s'", D->FileName); dbf_code = NOT_DB_FILE; return FAILURE; } /* | the size of each record */ D->RecLen = MakeInt(&Header[10]); /* | allocate some space for the current database record, if an error occurs | return error number */ if ((D->CurRecord = (DataRecord_t *)calloc(1, D->RecLen + 1)) == NULL) { dbf_msg_clr; dbf_code = errno; return FAILURE; } /* | set the current status for the header in to 'NotUpdated', if this gets | changed to 'Updated' the header info will need to be re-written */ D->hStatus = NotUpdated; /* | copy the current header info to a buffer in the database structure to | keep */ memcpy((char *)D->HeadProlog, (char *)Header, (int)sizeof(HeaderProlog_t)); /* | no fields defined yet, set to zero */ D->NumFields = 0; /* | loop until all field definitions are complete */ o = 1; i = 32; while (Header[i] != 0xD) { /* | decode each field description */ if ((rval = GetOneFieldDesc(D, (FieldDesc_t *)&Header[i], &tempFields[D->NumFields], &o)) != SUCCESS) { return rval; } /* | increment the number of fields in this header */ D->NumFields++; i += 32; } /* | all the fields have been defined, allocate space for them and copy them | to the database structure */ if ((D->Fields = (FieldRecord_t *)calloc(D->NumFields, sizeof(FieldRecord_t))) == NULL) { dbf_msg_clr; dbf_code = errno; return FAILURE; } nbytes = D->NumFields * sizeof(FieldRecord_t); memcpy((char *)D->Fields, (char *)tempFields, (int)nbytes); return SUCCESS; } /******************************************* ** Function: int GetHeader(dbfRecord_t *D) ** ** Description: ** Preform the read of the header information in the database file and ** decode the field definitions ** ** Return Values: ** * FAILURE - dbf_code set to actual error ** * SUCCESS - the routine completed without error ** ***************** *****************/ int GetHeader(dbfRecord_t *D) { Header_t H; int nbytes; /* | read the header information (up to MAX_HEADER bytes), on error return */ if ((nbytes = read(D->dFile, H, MAX_HEADER)) < 0) { sprintf(msg, "'%s'", D->FileName); dbf_code = READ_ERROR; return FAILURE; } /* | was able to read the header information, now decode it and return the | status from the decoding */ return(ProcessHeader(D, H, nbytes)); } /************************************************************* ** Function: int OpenDbf(int *handle, char *file, int flags) ** ** Description: ** This subroutine opens a database file and reads all the necessary ** parameters that are used to act upon the file. The database file ** incorporates a dBase III look-a-like format with header information ** at the beginning of the file describing the format of the fields and ** records. This information is stored into a structure to be passed to ** other database facilities. ** ** Return Values: ** * FAILURE - dbf_code set to actual error ** * SUCCESS - the routine completed without error ** ***************** *****************/ dbRet_t OpenDbf(SDDAS_INT *handle, char *file, int flags) { dbfRecord_t *D; dbRet_t rval; if ((D = GetNewDbfHandle(handle)) == NULL) return FAILURE; strcpy(D->FileName, file); /* | open the file defined as the database file, if there is an error return | error number */ if ((D->dFile = open(D->FileName, flags | O_BINARY)) < 0) { sprintf(msg, "'%s'", D->FileName); dbf_code = OPEN_ERROR; return FAILURE; } /* | read and decode all fields in this database, if there is an error close | the file and return the errno number */ if (GetHeader(D) != SUCCESS) { (void)close(D->dFile); return FAILURE; } /* | the fields have been defined, now set some of the status variables */ D->rStatus = NotUpdated; D->CurRec = 0; /* | if there are records in this database file read the first one */ if (D->NumRecs != 0) { if ((rval = GetDbfRecord(*handle, 1)) != SUCCESS) { return rval; } } /* | everything was OK */ dbf_code = 0; dbf_msg_clr; return SUCCESS; }