// dbfOpener.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include #include #include #include typedef unsigned char byte; typedef unsigned short word; typedef unsigned int dword; typedef unsigned char boole; enum { FALSE, TRUE }; class DBF { public: struct { char id[4]; int recordCount; short dataStart; int recordSize; word uk1; byte uk2[16]; } dbfHeader; struct field { char name[11]; char dataType; int offset; byte width; byte decPlace; byte uk2[14]; } *fields; private: FILE *fp; int ioresult; int recordNo; int stillOpen; boole century; int date; public: enum { OK, FILE_NOT_FOUND, FILE_NOT_DBF, END_OF_FILE, BEGIN_OF_FILE, FIELD_NOT_FOUND }; enum { AMERICAN, ANSI, BRITISH, FRENCH, GERMAN, ITALIAN, JAPAN, USA, MDY, DMY, YMD }; int IOResult(void); void Date(int date); int Date(void); void Open(char filename[]); void Close(void); void GoTop(void); void GoBottom(void); void GoNext(void); void GoPrev(void); int RecordNo(void); void Century(boole b); boole Century(void); DBF(char filename[]); DBF(void); ~DBF(); void Display(char fieldname[]); }; void DBF::Date(int date) { DBF::date = date; } int DBF::Date(void) { return date; } void DBF::Century(boole b) { century = b; } boole DBF::Century(void) { return century; } int DBF::IOResult(void) { return ioresult; } DBF::DBF() { date = MDY; century = FALSE; stillOpen = FALSE; } DBF::DBF(char filename[]) { date = MDY; century = FALSE; stillOpen = FALSE; Open(filename); } DBF::~DBF(void) { if (stillOpen) { fclose(fp); stillOpen = 0; delete fields; } } void DBF::GoTop(void) { recordNo = 0; fseek(fp, dbfHeader.dataStart, SEEK_SET); } void DBF::GoBottom(void) { fseek(fp, dbfHeader.dataStart + dbfHeader.recordCount * dbfHeader.recordSize, SEEK_SET); recordNo = dbfHeader.recordCount; ioresult = BEGIN_OF_FILE; } void DBF::GoNext(void) { recordNo++; fseek(fp, dbfHeader.recordCount + recordNo * dbfHeader.recordSize, SEEK_SET); if ( recordNo == dbfHeader.recordCount ) ioresult = END_OF_FILE; } void DBF::GoPrev(void) { recordNo--; fseek(fp, dbfHeader.dataStart + recordNo * dbfHeader.recordSize, SEEK_SET); if (recordNo == 0) ioresult = BEGIN_OF_FILE; } void DBF::Open(char filename[]) { int fieldNo; if (stillOpen) { fclose(fp); stillOpen = 0; delete fields; } recordNo = 0; fp = fopen(filename, "r+b"); if (fp == NULL) { ioresult = FILE_NOT_FOUND; } fread(&dbfHeader, 1, sizeof dbfHeader, fp); stillOpen = 1; fieldNo = dbfHeader.recordCount; fields = new field[ fieldNo ]; while (fieldNo--) { // 32 is header size fseek(fp, 32 + (fieldNo * 32), SEEK_SET); fread(&fields[fieldNo], sizeof(field), 1, fp); } } int DBF::RecordNo(void) { return recordNo; } void DBF::Close(void) { if (stillOpen) { fclose(fp); stillOpen = 0; delete fields; } } void DBF::Display(char fieldname[]) { int offset; byte width; char *buffer; if (!stillOpen) return; int fieldNo = dbfHeader.recordCount; ioresult = !OK; // tentatively while (fieldNo--) { if (stricmp(fields[fieldNo].name, fieldname) == 0) { offset = fields[fieldNo].offset; width = fields[fieldNo].width; ioresult = OK; break; } } if (ioresult != OK) { ioresult = FIELD_NOT_FOUND; return; } fseek(fp, dbfHeader.dataStart + recordNo * dbfHeader.recordSize, SEEK_SET); fseek(fp, offset, SEEK_CUR); buffer = new char[width + 1]; buffer[width] = NULL; fread(buffer, width, 1, fp); if (fields[fieldNo].dataType == 'D') { char year[5]; char month[3]; char date[3]; year[4] = NULL; month[2] = NULL; date[2] = NULL; memcpy(year, buffer, 4); memcpy(month, buffer + 4, 2); memcpy(date, buffer + 6, 4); if (century == FALSE) memcpy(year, year + 2, 3); switch(DBF::date) { case AMERICAN: case USA: case MDY: printf(month); break; case ANSI: case JAPAN: case YMD: printf(year); break; case BRITISH: case FRENCH: case GERMAN: case ITALIAN: case DMY: printf(date); break; } switch(DBF::date) { case AMERICAN: case BRITISH: case FRENCH: case JAPAN: case MDY: case DMY: case YMD: putchar('/'); break; case ANSI: case GERMAN: putchar('.'); break; case ITALIAN: case USA: putchar('-'); break; } switch(DBF::date) { case AMERICAN: case USA: case MDY: printf(date); break; case ANSI: case BRITISH: case FRENCH: case GERMAN: case ITALIAN: case JAPAN: case DMY: case YMD: printf(month); break; } switch(DBF::date) { case AMERICAN: case BRITISH: case FRENCH: case JAPAN: case MDY: case DMY: case YMD: putchar('/'); break; case ANSI: case GERMAN: putchar('.'); break; case ITALIAN: case USA: putchar('-'); break; } switch(DBF::date) { case AMERICAN: case BRITISH: case FRENCH: case GERMAN: case ITALIAN: case USA: case MDY: case DMY: printf(year); break; case ANSI: case JAPAN: case YMD: printf(date); break; } } else { printf(buffer); } delete buffer; } int main(int argc, char* argv[]) { if (argc < 3 ) { printf("Syntax %s filename.dbf fields", argv[0]); exit(0); } DBF Brother(argv[1]); if (Brother.IOResult() == DBF::FILE_NOT_FOUND) { printf("File not found\n"); exit(0); } Brother.Century(TRUE); Brother.Date(DBF::USA); do { for(int fieldNo = 2; fieldNo < argc; fieldNo++) { Brother.Display(argv[fieldNo]); putchar('\0'); } Brother.GoNext(); printf("\n"); } while(Brother.IOResult() != DBF::END_OF_FILE); getchar(); return 0; }