1639 lines
43 KiB
C++
1639 lines
43 KiB
C++
/***************************************************************************/
|
|
/* DBASE.C - This is the module containing the code to read and write */
|
|
/* dBASE files. */
|
|
/* */
|
|
/* (C) Copyright 1993-96 - SYWARE, Inc. - All rights reserved */
|
|
/***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "wbemidl.h"
|
|
#include "dbase.h"
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
#define s_lstrcpy(a, b) lstrcpy((LPSTR) a, (LPCSTR) b)
|
|
#define s_lstrcat(a, b) lstrcat((LPSTR) a, (LPCSTR) b)
|
|
#define s_lstrlen(a) lstrlen((LPCSTR) a)
|
|
#define s_lstrcmp(a, b) lstrcmp((LPCSTR) a, (LPCSTR) b)
|
|
|
|
/***************************************************************************/
|
|
#define FIRST_RECORD 0xFFFFFFFF
|
|
#define LAST_RECORD 0xFFFFFFFE
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseExtendedOpen(LPUSTR name, BOOL fReadOnly,
|
|
UWORD extraColumns, LPDBASEFILE FAR *lpf)
|
|
{
|
|
/*
|
|
HFILE hf;
|
|
UWORD columnCount;
|
|
UWORD recordLen;
|
|
HGLOBAL h;
|
|
LPDBASEFILE f;
|
|
UWORD i;
|
|
UCHAR FAR * ptr;
|
|
UCHAR fullname[DBASE_MAX_PATHNAME_SIZE+1];
|
|
|
|
// Get the filename
|
|
s_lstrcpy((char*)fullname, name);
|
|
ptr = fullname + s_lstrlen((char*)fullname);
|
|
while ((ptr != fullname) && (*ptr != PATH_SEPARATOR_CHAR) && (*ptr != ':') &&
|
|
(*ptr != '.'))
|
|
ptr--;
|
|
if (*ptr != '.')
|
|
s_lstrcat((char*)fullname, ".dbf");
|
|
|
|
// Open the file
|
|
if (fReadOnly)
|
|
hf = _lopen((LPCSTR)fullname, OF_READ);
|
|
else
|
|
hf = _lopen((LPCSTR)fullname, OF_READWRITE);
|
|
if (hf == HFILE_ERROR)
|
|
return DBASE_ERR_TABLEACCESSERROR;
|
|
|
|
//Figure out how many columns there are
|
|
if (HFILE_ERROR == _llseek(hf, DBASE_HEADER_SIZE_OFFSET, 0)) {
|
|
_lclose(hf);
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
if (sizeof(UWORD) != _lread(hf, &columnCount, sizeof(UWORD))) {
|
|
_lclose(hf);
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
columnCount = (columnCount - DBASE_HEADER_LENGTH - 1)/
|
|
DBASE_COLUMN_DESCR_LENGTH;
|
|
|
|
// Get record size
|
|
if (HFILE_ERROR == _llseek(hf, DBASE_RECORD_LENGTH_OFFSET, 0)) {
|
|
_lclose(hf);
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
if (sizeof(UWORD) != _lread(hf, &recordLen, sizeof(UWORD))) {
|
|
_lclose(hf);
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
|
|
// Allocate space for handle
|
|
h = GlobalAlloc (GMEM_MOVEABLE, (sizeof(DBASEFILE) - sizeof(DBASECOL)) +
|
|
(sizeof(DBASECOL) * (columnCount + extraColumns)) + recordLen);
|
|
if (h == NULL || (f = (LPDBASEFILE)GlobalLock (h)) == NULL)
|
|
{
|
|
_lclose(hf);
|
|
return DBASE_ERR_MEMALLOCFAIL;
|
|
}
|
|
|
|
// Read in the header
|
|
if (HFILE_ERROR == _llseek(hf, 0, 0)) {
|
|
GlobalUnlock(h);
|
|
GlobalFree(h);
|
|
_lclose(hf);
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
if (DBASE_HEADER_LENGTH != _lread(hf, f, DBASE_HEADER_LENGTH)) {
|
|
GlobalUnlock(h);
|
|
GlobalFree(h);
|
|
_lclose(hf);
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
if (f->encrypted != DBASE_NOT_ENCRYPTED) {
|
|
GlobalUnlock(h);
|
|
GlobalFree(h);
|
|
_lclose(hf);
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
f->hf = hf;
|
|
f->columnCount = columnCount;
|
|
f->sortArray = NULL;
|
|
f->currentRecord = 0;
|
|
f->record = ((UCHAR FAR *) (&(f->column))) +
|
|
((columnCount+extraColumns) * sizeof(DBASECOL));
|
|
f->headerDirty = FALSE;
|
|
f->recordDirty = FALSE;
|
|
f->newRecord = FALSE;
|
|
|
|
// Read in column definition
|
|
ptr = f->record + 1;
|
|
for (i = 0; (i < columnCount); i++) {
|
|
if (DBASE_COLUMN_DESCR_LENGTH !=
|
|
_lread(hf, &(f->column[i]), DBASE_COLUMN_DESCR_LENGTH)) {
|
|
GlobalUnlock(h);
|
|
GlobalFree(h);
|
|
_lclose(hf);
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
OemToAnsiBuff((LPCSTR) f->column[i].name, f->column[i].name,
|
|
DBASE_COLUMN_NAME_SIZE);
|
|
f->column[i].value = ptr;
|
|
ptr += f->column[i].length;
|
|
}
|
|
|
|
*lpf = f;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseFlushDirtyRecord(LPDBASEFILE f)
|
|
{
|
|
/*
|
|
LONG offset;
|
|
UCHAR c;
|
|
UDWORD currentRecord;
|
|
|
|
// Is there a dirty record?
|
|
if (f->recordDirty) {
|
|
|
|
// Yes. Write it back
|
|
f->recordDirty = FALSE;
|
|
if (f->sortArray == NULL)
|
|
currentRecord = f->currentRecord-1;
|
|
else
|
|
currentRecord = f->sortArray[f->currentRecord-1];
|
|
offset = f->headerSize + (currentRecord * f->recordSize);
|
|
if (HFILE_ERROR == _llseek(f->hf, offset, 0)) {
|
|
f->newRecord = FALSE;
|
|
f->currentRecord = 0;
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
AnsiToOemBuff((LPCSTR) f->record, f->record, f->recordSize);
|
|
if (f->recordSize != _lwrite(f->hf, (LPCSTR) f->record, f->recordSize)) {
|
|
f->newRecord = FALSE;
|
|
f->currentRecord = 0;
|
|
return DBASE_ERR_WRITEERROR;
|
|
}
|
|
|
|
// Was this a new record?
|
|
if (f->newRecord) {
|
|
|
|
// Yes. Write the end-of-data mark
|
|
f->newRecord = FALSE;
|
|
c = DBASE_FILE_END;
|
|
if (1 != _lwrite(f->hf, (LPCSTR) &c, 1)) {
|
|
f->currentRecord = 0;
|
|
return DBASE_ERR_WRITEERROR;
|
|
}
|
|
}
|
|
|
|
// Write back the header
|
|
f->headerDirty = TRUE;
|
|
}
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
|
|
}
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseQuickSortKeyCompare(LPDBASEFILE f, UWORD icol,
|
|
BOOL descending, UDWORD left,
|
|
UDWORD right, BOOL FAR *result)
|
|
|
|
/* Is the key of the left greater than or equal the key of the right? */
|
|
|
|
{
|
|
/*
|
|
SWORD err;
|
|
UWORD size;
|
|
UCHAR szLeft[255];
|
|
UCHAR szRight[255];
|
|
SDOUBLE dblLeft;
|
|
SDOUBLE dblRight;
|
|
BOOL nullLeft;
|
|
BOOL nullRight;
|
|
|
|
// Handle boundry conditions
|
|
if (left == LAST_RECORD) {
|
|
*result = TRUE;
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
if (right == FIRST_RECORD) {
|
|
*result = TRUE;
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
if (left == FIRST_RECORD) {
|
|
*result = FALSE;
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
if (right == LAST_RECORD) {
|
|
*result = FALSE;
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
// Position to the right record
|
|
if (HFILE_ERROR == _llseek(f->hf, f->headerSize + (right * f->recordSize),
|
|
0))
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
|
|
// Read the right record
|
|
size = _lread(f->hf, f->record, f->recordSize);
|
|
if (size != f->recordSize)
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
OemToAnsiBuff((LPCSTR) f->record, (LPSTR) f->record, f->recordSize);
|
|
*(f->record) = DBASE_RECORD_NOT_DELETED;
|
|
|
|
// Get the right key
|
|
switch (f->column[icol-1].type) {
|
|
case DBASE_CHAR:
|
|
case DBASE_LOGICAL:
|
|
case DBASE_DATE:
|
|
case DBASE_MEMO:
|
|
err = dBaseColumnCharVal(f, icol, 0, 255, szRight, &nullRight);
|
|
break;
|
|
case DBASE_NUMERIC:
|
|
case DBASE_FLOAT:
|
|
err = dBaseColumnNumVal(f, icol, &dblRight, &nullRight);
|
|
break;
|
|
}
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
|
|
// If right is null, return TRUE
|
|
if (nullRight) {
|
|
*result = TRUE;
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
// Position to the left record
|
|
if (HFILE_ERROR == _llseek(f->hf, f->headerSize + (left * f->recordSize),
|
|
0))
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
|
|
// Read the left record
|
|
size = _lread(f->hf, f->record, f->recordSize);
|
|
if (size != f->recordSize)
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
OemToAnsiBuff((LPCSTR) f->record, (LPSTR) f->record, f->recordSize);
|
|
*(f->record) = DBASE_RECORD_NOT_DELETED;
|
|
|
|
// Get the left key
|
|
switch (f->column[icol-1].type) {
|
|
case DBASE_CHAR:
|
|
case DBASE_LOGICAL:
|
|
case DBASE_DATE:
|
|
case DBASE_MEMO:
|
|
err = dBaseColumnCharVal(f, icol, 0, 255, szLeft, &nullLeft);
|
|
break;
|
|
case DBASE_NUMERIC:
|
|
case DBASE_FLOAT:
|
|
err = dBaseColumnNumVal(f, icol, &dblLeft, &nullLeft);
|
|
break;
|
|
}
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
|
|
// If left is null, return FALSE
|
|
if (nullRight) {
|
|
*result = FALSE;
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
// Compare the keys
|
|
switch (f->column[icol-1].type) {
|
|
case DBASE_CHAR:
|
|
case DBASE_LOGICAL:
|
|
case DBASE_DATE:
|
|
case DBASE_MEMO:
|
|
if (!descending) {
|
|
if (s_lstrcmp(szLeft, szRight) >= 0)
|
|
*result = TRUE;
|
|
else
|
|
*result = FALSE;
|
|
}
|
|
else {
|
|
if (s_lstrcmp(szLeft, szRight) <= 0)
|
|
*result = TRUE;
|
|
else
|
|
*result = FALSE;
|
|
}
|
|
break;
|
|
case DBASE_NUMERIC:
|
|
case DBASE_FLOAT:
|
|
if (!descending) {
|
|
if (dblLeft >= dblRight)
|
|
*result = TRUE;
|
|
else
|
|
*result = FALSE;
|
|
}
|
|
else {
|
|
if (dblLeft <= dblRight)
|
|
*result = TRUE;
|
|
else
|
|
*result = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
|
|
}
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseQuickSort(LPDBASEFILE f, UWORD icol, BOOL descending,
|
|
UDWORD FAR *sortArray, UDWORD left,
|
|
UDWORD right)
|
|
{
|
|
/*
|
|
UDWORD i;
|
|
UDWORD j;
|
|
UDWORD temp;
|
|
SWORD err;
|
|
BOOL result;
|
|
|
|
// Q1:
|
|
if (right <= left)
|
|
return DBASE_ERR_SUCCESS;
|
|
|
|
// Q2:
|
|
i = left;
|
|
j = right+1;
|
|
|
|
while (TRUE) {
|
|
|
|
// Q3:
|
|
while (TRUE) {
|
|
i++;
|
|
err = dBaseQuickSortKeyCompare(f, icol, descending,
|
|
sortArray[i], sortArray[left], &result);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
if (result)
|
|
break;
|
|
}
|
|
|
|
// Q4:
|
|
while (TRUE) {
|
|
j--;
|
|
err = dBaseQuickSortKeyCompare(f, icol, descending,
|
|
sortArray[left], sortArray[j], &result);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
if (result)
|
|
break;
|
|
}
|
|
|
|
// Q5:
|
|
if (j <= i)
|
|
break;
|
|
|
|
// Q6:
|
|
temp = sortArray[j];
|
|
sortArray[j] = sortArray[i];
|
|
sortArray[i] = temp;
|
|
}
|
|
|
|
// Q5:
|
|
temp = sortArray[left];
|
|
sortArray[left] = sortArray[j];
|
|
sortArray[j] = temp;
|
|
|
|
// Q7:
|
|
err = dBaseQuickSort(f, icol, descending, sortArray, left, j-1);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
|
|
// Q8:
|
|
err = dBaseQuickSort(f, icol, descending, sortArray, j+1, right);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
|
|
}
|
|
/***************************************************************************/
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseCreate(LPUSTR name)
|
|
{
|
|
/*
|
|
UCHAR FAR * ptr;
|
|
DBASEFILE header;
|
|
HFILE hf;
|
|
int i;
|
|
HANDLE h;
|
|
UCHAR NEAR *fullname;
|
|
UCHAR c;
|
|
HANDLE ht;
|
|
time_t *t;
|
|
struct tm *ts;
|
|
|
|
// Get the filename
|
|
h = LocalAlloc(LMEM_MOVEABLE, DBASE_MAX_PATHNAME_SIZE+1);
|
|
fullname = (UCHAR NEAR *) LocalLock(h);
|
|
lstrcpy(fullname, name);
|
|
ptr = fullname + lstrlen(fullname);
|
|
while ((ptr != fullname) && (*ptr != '\\') && (*ptr != ':') &&
|
|
(*ptr != '.'))
|
|
ptr--;
|
|
if (*ptr != '.')
|
|
lstrcat(fullname, ".dbf");
|
|
|
|
// Open the file
|
|
hf = _lcreat(fullname, 0);
|
|
if (hf == HFILE_ERROR) {
|
|
LocalUnlock(h);
|
|
LocalFree(h);
|
|
return DBASE_ERR_CREATEERROR;
|
|
}
|
|
|
|
// Set up the header
|
|
header.flag = DBASE_3_FILE;
|
|
ht = LocalAlloc(LMEM_MOVEABLE, sizeof(time_t));
|
|
t = (time_t NEAR *) LocalLock(ht);
|
|
time(t);
|
|
ts = localtime(t);
|
|
LocalUnlock(ht);
|
|
LocalFree(ht);
|
|
header.year = ts->tm_year;
|
|
header.month = ts->tm_mon + 1;
|
|
header.day = ts->tm_mday;
|
|
header.recordCount = 0;
|
|
header.headerSize = DBASE_HEADER_LENGTH + 1;
|
|
header.recordSize = 1;
|
|
for (i=0; (i < 2); i++)
|
|
header.reserved1[i] = 0;
|
|
header.transaction = 0;
|
|
header.encrypted = DBASE_NOT_ENCRYPTED;
|
|
for (i=0; (i < 12); i++)
|
|
header.reserved2[i] = 0;
|
|
header.mdx = DBASE_MDX_FLAG_OFF;
|
|
for (i=0; (i < 3); i++)
|
|
header.reserved3[i] = 0;
|
|
|
|
// Write the header
|
|
if (DBASE_HEADER_LENGTH != _lwrite(hf, (LPSTR) &header,
|
|
DBASE_HEADER_LENGTH)) {
|
|
_lclose(hf);
|
|
AnsiToOem(fullname, fullname);
|
|
#ifdef WIN32
|
|
DeleteFile(fullname);
|
|
#else
|
|
remove(fullname);
|
|
#endif
|
|
LocalUnlock(h);
|
|
LocalFree(h);
|
|
return DBASE_ERR_WRITEERROR;
|
|
}
|
|
|
|
// Write the end-of-columns mark
|
|
c = DBASE_END_OF_COLUMNS;
|
|
if (1 != _lwrite(hf, &c, 1)) {
|
|
_lclose(hf);
|
|
AnsiToOem(fullname, fullname);
|
|
#ifdef WIN32
|
|
DeleteFile(fullname);
|
|
#else
|
|
remove(fullname);
|
|
#endif
|
|
LocalUnlock(h);
|
|
LocalFree(h);
|
|
return DBASE_ERR_WRITEERROR;
|
|
}
|
|
|
|
// Write the end-of-data mark
|
|
c = DBASE_FILE_END;
|
|
if (1 != _lwrite(hf, &c, 1)) {
|
|
_lclose(hf);
|
|
AnsiToOem(fullname, fullname);
|
|
#ifdef WIN32
|
|
DeleteFile(fullname);
|
|
#else
|
|
remove(fullname);
|
|
#endif
|
|
LocalUnlock(h);
|
|
LocalFree(h);
|
|
return DBASE_ERR_WRITEERROR;
|
|
}
|
|
|
|
// Close the file
|
|
if (HFILE_ERROR == _lclose(hf)) {
|
|
AnsiToOem(fullname, fullname);
|
|
#ifdef WIN32
|
|
DeleteFile(fullname);
|
|
#else
|
|
remove(fullname);
|
|
#endif
|
|
LocalUnlock(h);
|
|
LocalFree(h);
|
|
return DBASE_ERR_CLOSEERROR;
|
|
}
|
|
LocalUnlock(h);
|
|
LocalFree(h);
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseAddColumn(LPUSTR name, LPUSTR colName, UCHAR type,
|
|
UCHAR length, UCHAR scale)
|
|
{
|
|
/*
|
|
LPDBASEFILE f;
|
|
LPSTR from;
|
|
int i;
|
|
LONG offset;
|
|
UCHAR c;
|
|
SWORD err;
|
|
|
|
// Check the column name
|
|
if (lstrlen(colName) > DBASE_COLUMN_NAME_SIZE)
|
|
return DBASE_ERR_NOTSUPPORTED;
|
|
|
|
// Check the length and scale
|
|
switch (type) {
|
|
case DBASE_CHAR:
|
|
if ((length == 0) || (length > 254))
|
|
return DBASE_ERR_NOTSUPPORTED;
|
|
scale = 0;
|
|
break;
|
|
case DBASE_NUMERIC:
|
|
case DBASE_FLOAT:
|
|
if ((length == 0) || (length > 19))
|
|
return DBASE_ERR_NOTSUPPORTED;
|
|
if (length == 1) {
|
|
if (scale != 0)
|
|
return DBASE_ERR_NOTSUPPORTED;
|
|
}
|
|
else if (((UCHAR) (scale+2)) > length)
|
|
return DBASE_ERR_NOTSUPPORTED;
|
|
break;
|
|
case DBASE_LOGICAL:
|
|
length = 1;
|
|
scale = 0;
|
|
break;
|
|
case DBASE_DATE:
|
|
length = 8;
|
|
scale = 0;
|
|
break;
|
|
case DBASE_MEMO:
|
|
return DBASE_ERR_NOTSUPPORTED;
|
|
default:
|
|
return DBASE_ERR_NOTSUPPORTED;
|
|
}
|
|
|
|
// Open the file
|
|
err = dBaseExtendedOpen(name, FALSE, 1, &f) ;
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
|
|
if (f->recordCount != 0) {
|
|
dBaseClose(f);
|
|
return DBASE_ERR_NOTSUPPORTED;
|
|
}
|
|
|
|
// Fill in the new entry
|
|
from = colName;
|
|
for (i=0; (i < DBASE_COLUMN_NAME_SIZE); i++) {
|
|
f->column[f->columnCount].name[i] = *from;
|
|
if (*from != 0)
|
|
from++;
|
|
}
|
|
f->column[f->columnCount].type = type;
|
|
for (i=0; (i < 4); i++)
|
|
f->column[f->columnCount].reserved1[i] = 0;
|
|
f->column[f->columnCount].length = length;
|
|
f->column[f->columnCount].scale = scale;
|
|
for (i=0; (i < 2); i++)
|
|
f->column[f->columnCount].reserved2[i] = 0;
|
|
f->column[f->columnCount].workarea = 0;
|
|
for (i=0; (i < 10); i++)
|
|
f->column[f->columnCount].reserved3[i] = 0;
|
|
f->column[f->columnCount].mdx = DBASE_MDX_FLAG_OFF;
|
|
f->column[f->columnCount].value = NULL;
|
|
|
|
// Write the new column information
|
|
offset = DBASE_HEADER_LENGTH + (f->columnCount*DBASE_COLUMN_DESCR_LENGTH);
|
|
if (HFILE_ERROR == _llseek(f->hf, offset, 0)) {
|
|
dBaseClose(f);
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
AnsiToOemBuff(f->column[f->columnCount].name,
|
|
f->column[f->columnCount].name, DBASE_COLUMN_NAME_SIZE);
|
|
if (DBASE_COLUMN_DESCR_LENGTH != _lwrite(f->hf, (LPSTR)
|
|
&(f->column[f->columnCount]), DBASE_COLUMN_DESCR_LENGTH)) {
|
|
dBaseClose(f);
|
|
return DBASE_ERR_WRITEERROR;
|
|
}
|
|
|
|
// Adust header information
|
|
(f->columnCount)++;
|
|
f->headerSize += DBASE_COLUMN_DESCR_LENGTH;
|
|
f->recordSize += length;
|
|
if (type == DBASE_FLOAT)
|
|
f->flag = DBASE_4_FILE;
|
|
|
|
// Put in end-of-columns mark
|
|
c = DBASE_END_OF_COLUMNS;
|
|
if (1 != _lwrite(f->hf, &c, 1)) {
|
|
dBaseClose(f);
|
|
return DBASE_ERR_WRITEERROR;
|
|
}
|
|
|
|
// Put in end-of-data mark
|
|
c = DBASE_FILE_END;
|
|
if (1 != _lwrite(f->hf, &c, 1)) {
|
|
dBaseClose(f);
|
|
return DBASE_ERR_WRITEERROR;
|
|
}
|
|
|
|
// Close the file
|
|
f->headerDirty = TRUE;
|
|
err = dBaseClose(f);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseOpen(LPUSTR name, BOOL fReadOnly, LPDBASEFILE FAR *lpf)
|
|
{
|
|
return dBaseExtendedOpen(name, fReadOnly, 0, lpf);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseColumnCount(LPDBASEFILE f, UWORD FAR *count)
|
|
{
|
|
// *count = f->columnCount;
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseColumnName(LPDBASEFILE f, UWORD icol, LPUSTR name)
|
|
{
|
|
/*
|
|
int i;
|
|
|
|
if ((icol > f->columnCount) || (icol <= 0))
|
|
return DBASE_ERR_NOSUCHCOLUMN;
|
|
|
|
for (i = 0; i < DBASE_COLUMN_NAME_SIZE; i++)
|
|
name[i] = f->column[icol-1].name[i];
|
|
name[DBASE_COLUMN_NAME_SIZE] = '\0';
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseColumnType(LPDBASEFILE f, UWORD icol, UCHAR FAR *type)
|
|
{
|
|
/*
|
|
if ((icol > f->columnCount) || (icol <= 0))
|
|
return DBASE_ERR_NOSUCHCOLUMN;
|
|
|
|
*type = f->column[icol-1].type;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseColumnLength(LPDBASEFILE f, UWORD icol, UCHAR FAR *len)
|
|
{
|
|
/*
|
|
if ((icol > f->columnCount) || (icol <= 0))
|
|
return DBASE_ERR_NOSUCHCOLUMN;
|
|
|
|
*len = f->column[icol-1].length;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseColumnScale(LPDBASEFILE f, UWORD icol, UCHAR FAR *scale)
|
|
{
|
|
/*
|
|
if ((icol > f->columnCount) || (icol <= 0))
|
|
return DBASE_ERR_NOSUCHCOLUMN;
|
|
|
|
*scale = f->column[icol-1].scale;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseSort(LPDBASEFILE f, UWORD icol, BOOL descending)
|
|
{
|
|
/*
|
|
SWORD err;
|
|
HANDLE h;
|
|
UDWORD FAR *sortArray;
|
|
UDWORD idx;
|
|
|
|
// Make sure column is really there
|
|
if ((icol > f->columnCount) || (icol < 0))
|
|
return DBASE_ERR_NOSUCHCOLUMN;
|
|
|
|
// Write back any pending writes
|
|
err = dBaseFlushDirtyRecord(f);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
|
|
// Remove sort order (if any)
|
|
if (f->sortArray != NULL) {
|
|
GlobalUnlock(GlobalPtrHandle (f->sortArray));
|
|
GlobalFree(GlobalPtrHandle(f->sortArray));
|
|
f->sortArray = NULL;
|
|
}
|
|
|
|
// Is there a new sort?
|
|
if (icol != 0) {
|
|
|
|
// Yes. Allocate space for new sort
|
|
h = GlobalAlloc (GMEM_MOVEABLE, (sizeof(UDWORD) * (f->recordCount + 2)));
|
|
if (h == NULL || (sortArray = (UDWORD FAR *)GlobalLock (h)) == NULL)
|
|
return DBASE_ERR_MEMALLOCFAIL;
|
|
|
|
// Fill in the sort array
|
|
sortArray[0] = FIRST_RECORD;
|
|
for (idx = 1; idx < f->recordCount+1; idx++)
|
|
sortArray[idx] = idx-1;
|
|
sortArray[f->recordCount+1] = LAST_RECORD;
|
|
|
|
// Sort the records
|
|
f->currentRecord = 1;
|
|
err = dBaseQuickSort(f, icol, descending, sortArray, 1, f->recordCount);
|
|
if (err != DBASE_ERR_SUCCESS) {
|
|
f->currentRecord = 0;
|
|
GlobalUnlock(h);
|
|
GlobalFree(h);
|
|
return err;
|
|
}
|
|
f->currentRecord = 0;
|
|
|
|
// Move the items into place
|
|
for (idx = 0; idx < f->recordCount; idx++)
|
|
sortArray[idx] = sortArray[idx+1];
|
|
sortArray[f->recordCount] = f->recordCount;
|
|
f->sortArray = sortArray;
|
|
}
|
|
|
|
// Position before record
|
|
f->currentRecord = 0;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseReadFirst(LPDBASEFILE f)
|
|
{
|
|
/*
|
|
LONG offset;
|
|
SWORD err;
|
|
UWORD size;
|
|
UDWORD currentRecord;
|
|
|
|
// Write back any pending writes
|
|
err = dBaseFlushDirtyRecord(f);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
|
|
// Position to the first record
|
|
if (f->sortArray == NULL)
|
|
currentRecord = 0;
|
|
else
|
|
currentRecord = f->sortArray[0];
|
|
offset = f->headerSize + (currentRecord * f->recordSize);
|
|
if (HFILE_ERROR == _llseek(f->hf, offset, 0))
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
|
|
// Read the record
|
|
size = _lread(f->hf, f->record, f->recordSize);
|
|
if (size == 1) {
|
|
if (*(f->record) == DBASE_FILE_END)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
else
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
if (size != f->recordSize)
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
f->currentRecord = 1;
|
|
|
|
// If this record is deleted, return next record
|
|
if (*(f->record) == DBASE_RECORD_DELETED)
|
|
return dBaseReadNext(f);
|
|
|
|
// Return record
|
|
OemToAnsiBuff(f->record, f->record, f->recordSize);
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseReadNext(LPDBASEFILE f)
|
|
{
|
|
/*
|
|
LONG offset;
|
|
SWORD err;
|
|
UWORD size;
|
|
UDWORD currentRecord;
|
|
|
|
// Write back any pending writes
|
|
err = dBaseFlushDirtyRecord(f);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
|
|
// Position to the next record
|
|
if (f->sortArray == NULL)
|
|
currentRecord = f->currentRecord;
|
|
else
|
|
currentRecord = f->sortArray[f->currentRecord];
|
|
offset = f->headerSize + (currentRecord * f->recordSize);
|
|
if (HFILE_ERROR == _llseek(f->hf, offset, 0))
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
|
|
// Read the record
|
|
size = _lread(f->hf, f->record, f->recordSize);
|
|
if (size == 1) {
|
|
if (*(f->record) == DBASE_FILE_END)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
else
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
if (size != f->recordSize)
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
f->currentRecord++;
|
|
|
|
// If this record is deleted, return next record
|
|
if (*(f->record) == DBASE_RECORD_DELETED)
|
|
return dBaseReadNext(f);
|
|
|
|
// Return record
|
|
OemToAnsiBuff(f->record, f->record, f->recordSize);
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseColumnCharVal(LPDBASEFILE f, UWORD icol, UDWORD offset,
|
|
SDWORD bufsize, UCHAR FAR *val,
|
|
BOOL FAR *isNull)
|
|
{
|
|
/*
|
|
|
|
LPDBASECOL lpCol;
|
|
UCHAR FAR *fromPtr;
|
|
UCHAR FAR *toPtr;
|
|
UCHAR i;
|
|
UWORD year;
|
|
UWORD month;
|
|
UWORD day;
|
|
*/
|
|
SWORD err;
|
|
/*
|
|
// Make sure data is really there
|
|
if ((icol > f->columnCount) || (icol <= 0))
|
|
return DBASE_ERR_NOSUCHCOLUMN;
|
|
if (f->currentRecord == 0)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
if (*(f->record) == DBASE_RECORD_DELETED)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
|
|
// Get the data
|
|
lpCol = &(f->column[icol-1]);
|
|
fromPtr = lpCol->value;
|
|
*/
|
|
err = DBASE_ERR_SUCCESS;
|
|
/*
|
|
switch (lpCol->type) {
|
|
case DBASE_CHAR:
|
|
toPtr = val;
|
|
*isNull = TRUE;
|
|
if (bufsize <= ((SDWORD) lpCol->length)) {
|
|
err = DBASE_ERR_TRUNCATION;
|
|
}
|
|
else {
|
|
bufsize = lpCol->length;
|
|
}
|
|
for (i=0; i < (UCHAR) bufsize; i++) {
|
|
if (*fromPtr != ' ')
|
|
*isNull = FALSE;
|
|
if (toPtr != NULL) {
|
|
*toPtr = *fromPtr;
|
|
toPtr++;
|
|
}
|
|
fromPtr++;
|
|
}
|
|
if (toPtr != NULL)
|
|
*toPtr = '\0';
|
|
break;
|
|
case DBASE_FLOAT:
|
|
case DBASE_NUMERIC:
|
|
i = lpCol->length;
|
|
while ((*fromPtr == ' ') && (i > 0)) {
|
|
fromPtr++;
|
|
i--;
|
|
}
|
|
toPtr = val;
|
|
*isNull = TRUE;
|
|
for (;i > 0; i--) {
|
|
if (toPtr != NULL) {
|
|
*toPtr = *fromPtr;
|
|
toPtr++;
|
|
}
|
|
fromPtr++;
|
|
*isNull = FALSE;
|
|
}
|
|
if (toPtr != NULL)
|
|
*toPtr = '\0';
|
|
break;
|
|
case DBASE_DATE:
|
|
if (*fromPtr == ' ')
|
|
*isNull = TRUE;
|
|
else {
|
|
*isNull = FALSE;
|
|
year = ((fromPtr[0] & 0x0F) * 1000) +
|
|
((fromPtr[1] & 0x0F) * 100) +
|
|
((fromPtr[2] & 0x0F) * 10) +
|
|
(fromPtr[3] & 0x0F);
|
|
month = ((fromPtr[4] & 0x0F) * 10) + (fromPtr[5] & 0x0F);
|
|
day = ((fromPtr[6] & 0x0F) * 10) + (fromPtr[7] & 0x0F);
|
|
if (val != NULL)
|
|
wsprintf(val, "%04d-%02d-%02d", year, month, day);
|
|
}
|
|
break;
|
|
case DBASE_LOGICAL:
|
|
switch (*fromPtr) {
|
|
case 'Y':
|
|
case 'y':
|
|
case 'T':
|
|
case 't':
|
|
case '1':
|
|
if (val != NULL)
|
|
lstrcpy(val, "1");
|
|
*isNull = FALSE;
|
|
break;
|
|
case 'N':
|
|
case 'n':
|
|
case 'F':
|
|
case 'f':
|
|
case '0':
|
|
if (val != NULL)
|
|
lstrcpy(val, "0");
|
|
*isNull = FALSE;
|
|
break;
|
|
case '?':
|
|
case ' ':
|
|
*isNull = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
case DBASE_MEMO:
|
|
*isNull = TRUE;
|
|
break;
|
|
}
|
|
if ((*isNull) && (val != NULL))
|
|
lstrcpy(val, "");
|
|
*/
|
|
return err;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseColumnNumVal(LPDBASEFILE f, UWORD icol,
|
|
SDOUBLE FAR *val, BOOL FAR *isNull)
|
|
{
|
|
/*
|
|
LPDBASECOL lpCol;
|
|
UCHAR i;
|
|
double d;
|
|
BOOL neg;
|
|
UCHAR FAR *fromPtr;
|
|
BOOL foundDecimalPoint;
|
|
short scale;
|
|
BOOL negexp;
|
|
short exp;
|
|
|
|
// Make sure data is really there
|
|
if ((icol > f->columnCount) || (icol <= 0))
|
|
return DBASE_ERR_NOSUCHCOLUMN;
|
|
if (f->currentRecord == 0)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
if (*(f->record) == DBASE_RECORD_DELETED)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
|
|
// Get the data
|
|
lpCol = &(f->column[icol-1]);
|
|
fromPtr = lpCol->value;
|
|
switch (lpCol->type) {
|
|
case DBASE_CHAR:
|
|
case DBASE_FLOAT:
|
|
case DBASE_NUMERIC:
|
|
*isNull = TRUE;
|
|
for (i=0; i < lpCol->length; i++) {
|
|
if (*fromPtr != ' ')
|
|
break;
|
|
fromPtr++;
|
|
}
|
|
|
|
neg = FALSE;
|
|
if (i < lpCol->length) {
|
|
if (*fromPtr == '-') {
|
|
neg = TRUE;
|
|
fromPtr++;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
d = 0.0;
|
|
scale = 0;
|
|
foundDecimalPoint = FALSE;
|
|
for (;i < lpCol->length; i++) {
|
|
if (!foundDecimalPoint && (*fromPtr == '.'))
|
|
foundDecimalPoint = TRUE;
|
|
else {
|
|
if ((*fromPtr == 'E') || (*fromPtr == 'e')) {
|
|
fromPtr++;
|
|
i++;
|
|
if (i < lpCol->length) {
|
|
if (*fromPtr == '-') {
|
|
negexp = TRUE;
|
|
fromPtr++;
|
|
i++;
|
|
}
|
|
else if (*fromPtr == '+') {
|
|
negexp = FALSE;
|
|
fromPtr++;
|
|
i++;
|
|
}
|
|
else
|
|
negexp = FALSE;
|
|
}
|
|
else
|
|
negexp = FALSE;
|
|
exp = 0;
|
|
for (;i < lpCol->length; i++) {
|
|
if ((*fromPtr < '0') || (*fromPtr > '9'))
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
exp = (exp * 10) + (*fromPtr - '0');
|
|
fromPtr++;
|
|
}
|
|
if (negexp)
|
|
scale = scale + exp;
|
|
else
|
|
scale = scale - exp;
|
|
break;
|
|
}
|
|
if ((*fromPtr < '0') || (*fromPtr > '9'))
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
d = (d * 10) + (*fromPtr - '0');
|
|
*isNull = FALSE;
|
|
if (foundDecimalPoint)
|
|
scale++;
|
|
}
|
|
fromPtr++;
|
|
}
|
|
|
|
for (; (0 < scale); scale--)
|
|
d /= 10;
|
|
for (; (0 > scale); scale++)
|
|
d *= 10;
|
|
|
|
if (val != NULL) {
|
|
if (neg)
|
|
*val = -d;
|
|
else
|
|
*val = d;
|
|
}
|
|
break;
|
|
case DBASE_DATE:
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
case DBASE_LOGICAL:
|
|
switch (*fromPtr) {
|
|
case 'Y':
|
|
case 'y':
|
|
case 'T':
|
|
case 't':
|
|
case '1':
|
|
if (val != NULL)
|
|
*val = 1.0;
|
|
*isNull = FALSE;
|
|
break;
|
|
case 'N':
|
|
case 'n':
|
|
case 'F':
|
|
case 'f':
|
|
case '0':
|
|
if (val != NULL)
|
|
*val = 0.0;
|
|
*isNull = FALSE;
|
|
break;
|
|
case '?':
|
|
case ' ':
|
|
*isNull = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
case DBASE_MEMO:
|
|
*isNull = TRUE;
|
|
break;
|
|
}
|
|
if ((val != NULL) && (*isNull))
|
|
*val = 0.0;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseAddRecord(LPDBASEFILE f)
|
|
{
|
|
/*
|
|
UWORD i;
|
|
UCHAR FAR * ptr;
|
|
SWORD err;
|
|
|
|
// Write dirty record
|
|
err = dBaseFlushDirtyRecord(f);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
|
|
// Remove sort order (if any)
|
|
if (f->sortArray != NULL) {
|
|
GlobalUnlock(GlobalPtrHandle(f->sortArray));
|
|
GlobalFree(GlobalPtrHandle(f->sortArray));
|
|
f->sortArray = NULL;
|
|
}
|
|
|
|
// Create null record
|
|
ptr = f->record;
|
|
for (i=0; i < f->recordSize; i++) {
|
|
*ptr = ' ';
|
|
ptr++;
|
|
}
|
|
f->recordDirty = TRUE;
|
|
f->newRecord = TRUE;
|
|
|
|
// Increment record count
|
|
f->recordCount++;
|
|
f->headerDirty = TRUE;
|
|
|
|
// Reset current record
|
|
f->currentRecord = f->recordCount;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseSetColumnCharVal(LPDBASEFILE f, UWORD icol,
|
|
UCHAR FAR *val, SDWORD size)
|
|
{
|
|
/*
|
|
LPDBASECOL lpCol;
|
|
UCHAR FAR *fromPtr;
|
|
UCHAR FAR *toPtr;
|
|
UCHAR FAR *decimalLocation;
|
|
UCHAR FAR *valStart;
|
|
UCHAR FAR *valEnd;
|
|
UCHAR FAR *ptr;
|
|
UCHAR length;
|
|
UCHAR i;
|
|
SWORD extraZeros;
|
|
BOOL negNeeded;
|
|
BOOL foundExp;
|
|
SWORD err;
|
|
|
|
// Make sure data is really there
|
|
if ((icol > f->columnCount) || (icol <= 0))
|
|
return DBASE_ERR_NOSUCHCOLUMN;
|
|
if (f->currentRecord == 0)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
if (*(f->record) == DBASE_RECORD_DELETED)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
|
|
// Set value
|
|
lpCol = &(f->column[icol-1]);
|
|
toPtr = lpCol->value;
|
|
err = DBASE_ERR_SUCCESS;
|
|
switch (lpCol->type) {
|
|
case DBASE_CHAR:
|
|
fromPtr = val;
|
|
for (i=0; i < lpCol->length; i++) {
|
|
if (((SDWORD) i) == size)
|
|
break;
|
|
*toPtr = *fromPtr;
|
|
toPtr++;
|
|
fromPtr++;
|
|
}
|
|
for (; i < lpCol->length; i++) {
|
|
*toPtr = ' ';
|
|
toPtr++;
|
|
}
|
|
if (((SDWORD) lpCol->length) < size)
|
|
err = DBASE_ERR_TRUNCATION;
|
|
break;
|
|
case DBASE_FLOAT:
|
|
case DBASE_NUMERIC:
|
|
|
|
// If a zero length string is specifed, point to a zero
|
|
if ((lpCol->scale == 0) && (size == 0)) {
|
|
val = "0";
|
|
size = 1;
|
|
}
|
|
|
|
// Point at start of value
|
|
length = lpCol->length - 1;
|
|
valStart = val;
|
|
if (*valStart == '-') {
|
|
valStart++;
|
|
}
|
|
|
|
// Make sure all characters are legal and find decimal point
|
|
foundExp = FALSE;
|
|
decimalLocation = NULL;
|
|
fromPtr = valStart;
|
|
i = 0;
|
|
while (((SDWORD) i) < size) {
|
|
if (*fromPtr == '\0')
|
|
break;
|
|
else if (*fromPtr == '.') {
|
|
if ((decimalLocation != NULL) || (foundExp))
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
decimalLocation = fromPtr;
|
|
}
|
|
else if ((*fromPtr == 'E') || (*fromPtr == 'e')) {
|
|
if (foundExp)
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
foundExp = TRUE;
|
|
if ((*fromPtr == '-') || (*fromPtr == '+')) {
|
|
fromPtr++;
|
|
i++;
|
|
}
|
|
}
|
|
else if (!(IsCharAlphaNumeric(*fromPtr)) || IsCharAlpha(*fromPtr))
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
fromPtr++;
|
|
i++;
|
|
}
|
|
|
|
// Scientific notation?
|
|
if (foundExp) {
|
|
|
|
// Yes. Error if not enough room for value
|
|
if (size > (SDWORD) lpCol->length)
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
|
|
// Copy the value
|
|
for (i=0; (SWORD) i < (SWORD) lpCol->length - lstrlen(val); i++) {
|
|
*toPtr = ' ';
|
|
toPtr++;
|
|
}
|
|
fromPtr = val;
|
|
while (*fromPtr) {
|
|
*toPtr = *fromPtr;
|
|
toPtr++;
|
|
fromPtr++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Find end of value
|
|
valEnd = fromPtr-1;
|
|
if (decimalLocation == valEnd) {
|
|
valEnd--;
|
|
decimalLocation = NULL;
|
|
}
|
|
|
|
// Truncate extra characters at end
|
|
if (decimalLocation != NULL) {
|
|
if (lpCol->scale == 0) {
|
|
valEnd = decimalLocation-1;
|
|
decimalLocation = NULL;
|
|
}
|
|
else {
|
|
if ((SWORD) lpCol->scale < (valEnd - decimalLocation)) {
|
|
valEnd = decimalLocation + lpCol->scale;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Figure out how many extra zeros need to be added at end
|
|
if (lpCol->scale == 0)
|
|
extraZeros = 0;
|
|
else if (decimalLocation == NULL)
|
|
extraZeros = lpCol->scale + 1;
|
|
else
|
|
extraZeros = lpCol->scale - (valEnd - decimalLocation);
|
|
|
|
// Shave off extra characters in front
|
|
while ((SWORD) length < (valEnd - valStart) + 1 + extraZeros)
|
|
valStart++;
|
|
|
|
// Put in leading spaces
|
|
for (i=0;
|
|
(SWORD) i < (length - (valEnd - valStart + 1) - extraZeros);
|
|
i++) {
|
|
*toPtr = ' ';
|
|
toPtr++;
|
|
}
|
|
|
|
// Put in sign if needed
|
|
negNeeded = FALSE;
|
|
if (*val == '-') {
|
|
for (ptr = valStart; ptr <= valEnd; ptr++) {
|
|
if ((*ptr != '0') && (*ptr != '.')) {
|
|
negNeeded = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (negNeeded)
|
|
*toPtr = '-';
|
|
else
|
|
*toPtr = ' ';
|
|
toPtr++;
|
|
|
|
// Put in value
|
|
while (valStart <= valEnd) {
|
|
*toPtr = *valStart;
|
|
toPtr++;
|
|
valStart++;
|
|
}
|
|
|
|
// Put in required trailing zeros
|
|
if (extraZeros == lpCol->scale + 1) {
|
|
*toPtr = '.';
|
|
toPtr++;
|
|
extraZeros--;
|
|
}
|
|
while (extraZeros > 0) {
|
|
*toPtr = '0';
|
|
toPtr++;
|
|
extraZeros--;
|
|
}
|
|
break;
|
|
|
|
case DBASE_DATE:
|
|
// Make sure value is legal
|
|
if (size != 10)
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
for (i=0; i < 10; i++) {
|
|
switch (i) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 6:
|
|
case 9:
|
|
if (!(IsCharAlphaNumeric(val[i])) || IsCharAlpha(val[i]))
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
break;
|
|
case 4:
|
|
case 7:
|
|
if (val[i] != '-')
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
break;
|
|
case 5:
|
|
if ((val[i] < '0') || (val[i] > '1'))
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
break;
|
|
case 8:
|
|
if ((val[i] < '0') && (val[i] > '3'))
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
if ((val[i] == '3') && (val[i+1] > '1'))
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Copy the value
|
|
for (i=0; i < 4; i++) {
|
|
*toPtr = val[i];
|
|
toPtr++;
|
|
}
|
|
for (i=5; i < 7; i++) {
|
|
*toPtr = val[i];
|
|
toPtr++;
|
|
}
|
|
for (i=8; i < 10; i++) {
|
|
*toPtr = val[i];
|
|
toPtr++;
|
|
}
|
|
break;
|
|
case DBASE_LOGICAL:
|
|
if (size != 1)
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
switch (*val) {
|
|
case 'Y':
|
|
case 'y':
|
|
case 'T':
|
|
case 't':
|
|
case '1':
|
|
*toPtr = 'Y';
|
|
break;
|
|
case 'N':
|
|
case 'n':
|
|
case 'F':
|
|
case 'f':
|
|
case '0':
|
|
*toPtr = 'N';
|
|
break;
|
|
case '?':
|
|
case ' ':
|
|
*toPtr = '?';
|
|
break;
|
|
default:
|
|
return DBASE_ERR_CONVERSIONERROR;
|
|
}
|
|
break;
|
|
case DBASE_MEMO:
|
|
break;
|
|
}
|
|
f->recordDirty = TRUE;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseSetColumnNull(LPDBASEFILE f, UWORD icol)
|
|
{
|
|
/*
|
|
UCHAR i;
|
|
LPDBASECOL lpCol;
|
|
|
|
// Make sure data is really there
|
|
if ((icol > f->columnCount) || (icol <= 0))
|
|
return DBASE_ERR_NOSUCHCOLUMN;
|
|
if (f->currentRecord == 0)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
if (*(f->record) == DBASE_RECORD_DELETED)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
|
|
// Set value
|
|
lpCol = &(f->column[icol-1]);
|
|
if (lpCol->type == DBASE_MEMO)
|
|
return DBASE_ERR_NOTSUPPORTED;
|
|
for (i=0; (i < f->column[icol-1].length); i++)
|
|
f->column[icol-1].value[i] = ' ';
|
|
f->recordDirty = TRUE;
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseDeleteRecord(LPDBASEFILE f)
|
|
{
|
|
/*
|
|
if (f->currentRecord == 0)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
if (*(f->record) == DBASE_RECORD_DELETED)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
|
|
if (f->newRecord) {
|
|
f->recordDirty = FALSE;
|
|
f->newRecord = FALSE;
|
|
f->recordCount--;
|
|
f->headerDirty = TRUE;
|
|
f->currentRecord = 0;
|
|
}
|
|
else {
|
|
*(f->record) = DBASE_RECORD_DELETED;
|
|
f->recordDirty = TRUE;
|
|
}
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
/***************************************************************************/
|
|
SWORD FAR PASCAL dBaseGetBookmark(LPDBASEFILE f, UDWORD far *b)
|
|
{
|
|
/*
|
|
// Make sure data is really there
|
|
if (f->currentRecord == 0)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
if (*(f->record) == DBASE_RECORD_DELETED)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
|
|
if (f->sortArray == NULL)
|
|
*b = f->currentRecord-1;
|
|
else
|
|
*b = f->sortArray[f->currentRecord-1];
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
/***************************************************************************/
|
|
SWORD FAR PASCAL dBasePosition(LPDBASEFILE f, UDWORD b)
|
|
{
|
|
/*
|
|
LONG offset;
|
|
SWORD err;
|
|
UWORD size;
|
|
|
|
// Write back any pending writes
|
|
err = dBaseFlushDirtyRecord(f);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
|
|
// Position to the specified record
|
|
offset = f->headerSize + (b * f->recordSize);
|
|
if (HFILE_ERROR == _llseek(f->hf, offset, 0))
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
|
|
// Read the record
|
|
size = _lread(f->hf, f->record, f->recordSize);
|
|
if (size == 1) {
|
|
if (*(f->record) == DBASE_FILE_END)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
else
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
}
|
|
if (size != f->recordSize)
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
f->currentRecord = b+1;
|
|
|
|
// If this record is deleted, return error
|
|
if (*(f->record) == DBASE_RECORD_DELETED)
|
|
return DBASE_ERR_NODATAFOUND;
|
|
|
|
// Return record
|
|
OemToAnsiBuff(f->record, f->record, f->recordSize);
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseClose(LPDBASEFILE f)
|
|
{
|
|
/*
|
|
SWORD err;
|
|
HANDLE ht;
|
|
time_t *t;
|
|
struct tm *ts;
|
|
|
|
if (f->headerDirty) {
|
|
ht = LocalAlloc(LMEM_MOVEABLE, sizeof(time_t));
|
|
t = (time_t NEAR *) LocalLock(ht);
|
|
time(t);
|
|
ts = localtime(t);
|
|
LocalUnlock(ht);
|
|
LocalFree(ht);
|
|
f->year = ts->tm_year;
|
|
f->month = ts->tm_mon + 1;
|
|
f->day = ts->tm_mday;
|
|
if (HFILE_ERROR == _llseek(f->hf, 0, 0))
|
|
return DBASE_ERR_CORRUPTFILE;
|
|
if (DBASE_HEADER_LENGTH != _lwrite(f->hf, (LPSTR) f, DBASE_HEADER_LENGTH))
|
|
return DBASE_ERR_WRITEERROR;
|
|
}
|
|
err = dBaseFlushDirtyRecord(f);
|
|
if (err != DBASE_ERR_SUCCESS)
|
|
return err;
|
|
if (HFILE_ERROR == _lclose(f->hf))
|
|
return DBASE_ERR_CLOSEERROR;
|
|
if (f->sortArray != NULL) {
|
|
GlobalUnlock(GlobalPtrHandle(f->sortArray));
|
|
GlobalFree(GlobalPtrHandle(f->sortArray));
|
|
}
|
|
GlobalUnlock(GlobalPtrHandle(f));
|
|
GlobalFree(GlobalPtrHandle(f));
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
SWORD FAR PASCAL dBaseDestroy(LPUSTR name)
|
|
{
|
|
/*
|
|
UCHAR FAR * ptr;
|
|
HANDLE h;
|
|
UCHAR NEAR *fullname;
|
|
|
|
// Get the filename
|
|
h = LocalAlloc(LMEM_MOVEABLE, DBASE_MAX_PATHNAME_SIZE+1);
|
|
fullname = (UCHAR NEAR *) LocalLock(h);
|
|
lstrcpy(fullname, name);
|
|
ptr = fullname + lstrlen(fullname);
|
|
while ((ptr != fullname) && (*ptr != '\\') && (*ptr != ':') &&
|
|
(*ptr != '.'))
|
|
ptr--;
|
|
if (*ptr != '.')
|
|
lstrcat(fullname, ".dbf");
|
|
|
|
AnsiToOem(fullname, fullname);
|
|
#ifdef WIN32
|
|
DeleteFile(fullname);
|
|
#else
|
|
remove(fullname);
|
|
#endif
|
|
LocalUnlock(h);
|
|
LocalFree(h);
|
|
*/
|
|
return DBASE_ERR_SUCCESS;
|
|
}
|
|
/***************************************************************************/
|
|
|