1498 lines
43 KiB
C
Executable File
1498 lines
43 KiB
C
Executable File
/* d4open.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
|
|
|
|
#include "d4all.h"
|
|
#ifdef __TURBOC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifdef S4OFF_MEMO
|
|
extern char f4memoNullChar ;
|
|
#endif
|
|
|
|
/* */
|
|
#ifdef S4UNIX
|
|
#include <sys/stat.h>
|
|
#else
|
|
#include "sys\stat.h"
|
|
#endif
|
|
/* */
|
|
|
|
static DATA4FILE *data4reopen( DATA4FILE *, char ** ) ;
|
|
|
|
static DATA4 *d4openInit( CODE4 *c4 )
|
|
{
|
|
DATA4 *d4 ;
|
|
#ifdef S4STAND_ALONE
|
|
#ifndef S4OFF_TRAN
|
|
int rc;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef S4VBASIC
|
|
if ( c4parm_check( c4, 1, E94301 ) )
|
|
return 0 ;
|
|
#endif
|
|
|
|
if ( error4code( c4 ) < 0 )
|
|
return 0 ;
|
|
|
|
#ifdef E4ANALYZE
|
|
if ( c4->debugInt != 0x5281 )
|
|
{
|
|
error4( 0, e4result, E81301 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
#ifdef S4STAND_ALONE
|
|
#ifndef S4OFF_TRAN
|
|
if ( c4->logOpen )
|
|
{
|
|
rc = code4logOpen( c4, 0, 0 ) ;
|
|
if ( rc < 0 )
|
|
return 0 ;
|
|
else
|
|
error4set( c4, 0 ) ; /* remove r4open if it already existed */
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef S4CLIENT
|
|
#ifdef E4ANALYZE
|
|
#ifndef S4STAND_ALONE
|
|
if ( c4->currentClient == 0 )
|
|
{
|
|
error4( c4, e4struct, E94301 ) ;
|
|
return 0 ;
|
|
}
|
|
if ( c4->currentClient->trans.c4trans == 0 )
|
|
{
|
|
error4( c4, e4struct, E94301 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
if ( c4->dataMemory == 0 )
|
|
{
|
|
c4->dataMemory = mem4create( c4, c4->memStartData, sizeof(DATA4), c4->memExpandData, 0 ) ;
|
|
if ( c4->dataMemory == 0 )
|
|
{
|
|
#ifdef E4STACK
|
|
error4stack( c4, e4memory, E94301 ) ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
}
|
|
d4 = (DATA4 *)mem4alloc( c4->dataMemory ) ;
|
|
if ( d4 == 0 )
|
|
{
|
|
#ifdef E4STACK
|
|
error4stack( c4, e4memory, E94301 ) ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
|
|
#ifdef S4VBASIC
|
|
d4->debugInt = E4DEBUG_INT ;
|
|
#endif
|
|
d4->codeBase = c4 ;
|
|
|
|
#ifdef S4SERVER
|
|
d4->clientId = 1L ; /* should get overridden at a later point, unless this is a server-only data file */
|
|
d4->serverId = c4->server->serverDataCount ;
|
|
c4->server->serverDataCount++ ;
|
|
d4->trans = &c4->currentClient->trans ;
|
|
l4add( tran4dataList( d4->trans ), d4 ) ;
|
|
#else
|
|
d4->trans = &c4->c4trans.trans ;
|
|
l4add( tran4dataList( (&(c4->c4trans.trans)) ), d4 ) ;
|
|
#endif
|
|
|
|
return d4 ;
|
|
}
|
|
|
|
static int d4openConclude( DATA4 *d4, const char *name, char *info )
|
|
{
|
|
CODE4 *c4 ;
|
|
int iFields, fieldType ;
|
|
unsigned int recOffset ;
|
|
long recWidth ;
|
|
#ifdef S4CLIENT_OR_FOX
|
|
int nullCount ;
|
|
#endif
|
|
char fieldBuf[2] ;
|
|
FIELD4IMAGE *image ;
|
|
#ifndef S4CLIENT
|
|
#ifdef S4CLIPPER
|
|
#ifndef S4OFF_INDEX
|
|
char nameBuf[258] ;
|
|
#else
|
|
#ifndef S4OFF_TRAN
|
|
#ifndef S4OFF_WRITE
|
|
char nameBuf[258] ;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#else
|
|
#ifndef S4OFF_TRAN
|
|
#ifndef S4OFF_WRITE
|
|
char nameBuf[258] ;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#ifndef S4OFF_WRITE
|
|
#ifndef S4OFF_TRAN
|
|
TRAN4 *trans ;
|
|
int tranCode ;
|
|
/* */
|
|
struct stat bufStat ;
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
long connectionId, rcl ;
|
|
short rc ;
|
|
#endif
|
|
#endif
|
|
#ifndef S4OFF_INDEX
|
|
INDEX4 *i4 ;
|
|
#ifndef S4SERVER
|
|
#ifndef S4CLIPPER
|
|
int oldSingleOpen ;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#else
|
|
#ifndef S4OFF_INDEX
|
|
char nameBuf[258] ;
|
|
#endif
|
|
#endif
|
|
#ifndef S4OFF_MEMO
|
|
int i_memo ;
|
|
#endif
|
|
|
|
c4 = d4->codeBase ;
|
|
|
|
#ifdef E4ANALYZE
|
|
if ( d4->dataFile->nFields == 0 )
|
|
return error4describe( c4, e4struct, E94301, name, 0, 0 ) ;
|
|
#endif
|
|
|
|
u4namePiece( d4->alias, sizeof( d4->alias ), name, 0, 0 ) ;
|
|
d4->alias[ sizeof( d4->alias ) - 1 ] = 0 ;
|
|
|
|
recWidth = dfile4recWidth( d4->dataFile ) ;
|
|
if ( ( ( recWidth + 50L + 1L ) * 2L + (long)sizeof( FIELD4 ) * (long)d4->dataFile->nFields ) > (long)UINT_MAX ) /* try allocating records and fields together, 50 bytes for overhead */
|
|
{
|
|
d4->groupRecordAlloc = (char *)u4allocFree( c4, (recWidth + 1L) * 2L + (long)sizeof( FIELD4 ) * (long)d4->dataFile->nFields ) ;
|
|
if ( d4->groupRecordAlloc != 0 )
|
|
{
|
|
d4->record = d4->groupRecordAlloc ;
|
|
d4->recordOld = d4->groupRecordAlloc + recWidth + 1 ;
|
|
d4->fields = (FIELD4 *)(d4->groupRecordAlloc + 2 * ( recWidth + 1 ) ) ;
|
|
}
|
|
}
|
|
|
|
if ( d4->groupRecordAlloc == 0 )
|
|
{
|
|
d4->record = (char *)u4allocFree( c4, recWidth + 1 ) ;
|
|
d4->recordOld = (char *)u4allocFree( c4, recWidth + 1 ) ;
|
|
d4->fields = (FIELD4 *)u4allocFree( c4, sizeof( FIELD4 ) * (long)d4->dataFile->nFields ) ;
|
|
}
|
|
if ( d4->record == 0 || d4->recordOld == 0 || d4->fields == 0 )
|
|
return error4stack( c4, e4memory, E94301 ) ;
|
|
|
|
recOffset = 1 ;
|
|
|
|
#ifdef S4CLIENT_OR_FOX
|
|
nullCount = 0 ;
|
|
#endif
|
|
|
|
if ( !( error4code( c4 ) < 0 ) )
|
|
for ( iFields = 0 ; iFields < d4->dataFile->nFields ; iFields++ )
|
|
{
|
|
image = (FIELD4IMAGE *)( info + iFields * 32 ) ;
|
|
u4ncpy( d4->fields[iFields].name, image->name, sizeof( d4->fields->name ) ) ;
|
|
|
|
u4ncpy( fieldBuf, &image->type, 2 ) ;
|
|
c4upper( fieldBuf ) ;
|
|
d4->fields[iFields].type = *fieldBuf ;
|
|
fieldType = d4->fields[iFields].type ;
|
|
#ifdef S4CLIENT_OR_FOX
|
|
if ( d4version( d4 ) == 0x30 ) /* FOX 3.0 */
|
|
{
|
|
d4->fields[iFields].null = ( image->nullBinary & 0x02 ) ? 1 : 0 ;
|
|
if ( d4->fields[iFields].null == 1 )
|
|
{
|
|
d4->fields[iFields].nullBit = nullCount ;
|
|
nullCount++ ;
|
|
}
|
|
if ( image->nullBinary & 0x04 )
|
|
d4->fields[iFields].binary = 1 ;
|
|
else
|
|
{
|
|
if ( fieldType == r4memo || fieldType == r4gen ) /* memo fields are also stored binary */
|
|
d4->fields[iFields].binary = 2 ;
|
|
else
|
|
d4->fields[iFields].binary = 0 ;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
switch( fieldType )
|
|
{
|
|
#ifdef S4CLIENT_OR_FOX
|
|
case r4int:
|
|
#endif
|
|
case r4log:
|
|
case r4date:
|
|
d4->fields[iFields].len = image->len ;
|
|
break ;
|
|
case r4double: /* same as r4bin */
|
|
if ( d4version( d4 ) == 0x30 ) /* double */
|
|
{
|
|
d4->fields[iFields].len = image->len ;
|
|
d4->fields[iFields].dec = image->dec ;
|
|
}
|
|
else /* binary */
|
|
d4->fields[iFields].len = image->len ;
|
|
break ;
|
|
case r4num:
|
|
case r4float:
|
|
#ifdef S4CLIENT_OR_FOX
|
|
case r4currency:
|
|
case r4dateTime:
|
|
#endif
|
|
d4->fields[iFields].len = image->len ;
|
|
d4->fields[iFields].dec = image->dec ;
|
|
break ;
|
|
case r4memo:
|
|
case r4gen:
|
|
/* #ifdef S4OFF_MEMO */
|
|
/* d4->fields[iFields].memo = (F4MEMO *)&f4memoNullChar ; */
|
|
/* #endif */
|
|
d4->fields[iFields].len = image->len ;
|
|
break ;
|
|
default:
|
|
d4->fields[iFields].len = image->len + ( image->dec << 8 ) ;
|
|
break ;
|
|
}
|
|
|
|
#ifdef S4VBASIC
|
|
d4->fields[iFields].debugInt = E4DEBUG_INT ;
|
|
#endif
|
|
d4->fields[iFields].offset = recOffset ;
|
|
recOffset += d4->fields[iFields].len ;
|
|
d4->fields[iFields].data = d4 ;
|
|
}
|
|
|
|
#ifndef S4OFF_MEMO
|
|
if ( d4->dataFile->nFieldsMemo > 0 && !( error4code( c4 ) < 0 ) )
|
|
{
|
|
i_memo = 0 ;
|
|
|
|
d4->fieldsMemo = (F4MEMO *)u4allocFree( c4, (long)sizeof(F4MEMO) * d4->dataFile->nFieldsMemo ) ;
|
|
#ifdef E4STACK
|
|
if ( d4->fieldsMemo == 0 )
|
|
error4stack( c4, e4memory, E94301 ) ;
|
|
#endif
|
|
if ( d4->fieldsMemo != 0 )
|
|
for ( iFields = 0 ; iFields < d4->dataFile->nFields ; iFields++ )
|
|
{
|
|
fieldType = d4->fields[iFields].type ;
|
|
if ( fieldType == r4memo || fieldType == r4gen || ( fieldType == r4bin && d4version( d4 ) != 0x30 ) )
|
|
{
|
|
d4->fields[iFields].memo = d4->fieldsMemo+i_memo ;
|
|
d4->fieldsMemo[i_memo].status = 1 ;
|
|
d4->fieldsMemo[i_memo].field = d4->fields+iFields ;
|
|
i_memo++ ;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( error4code( c4 ) < 0 )
|
|
return -1 ;
|
|
|
|
d4->recNum = d4->recNumOld = -1 ;
|
|
|
|
d4blank( d4 ) ;
|
|
memcpy( d4->recordOld, d4->record, (unsigned)recWidth ) ;
|
|
d4->recordChanged = 0 ;
|
|
|
|
d4->record[recWidth] = 0 ;
|
|
d4->recordOld[recWidth] = 0 ;
|
|
|
|
#ifndef S4OFF_INDEX
|
|
#ifdef S4CLIENT
|
|
/* client will get all the index tags if autoOpen set to 1, else
|
|
will get none -- this is an undocumented side-effect */
|
|
if ( d4->dataFile->indexes.nLink > 0 && c4->autoOpen == 1 )
|
|
{
|
|
u4namePiece( nameBuf, sizeof( nameBuf ), name, 0, 0 ) ;
|
|
if ( i4setup( c4, d4, nameBuf, 1, 0 ) < 0 )
|
|
return -1 ;
|
|
}
|
|
#else
|
|
#ifdef S4CLIPPER
|
|
if ( c4->autoOpen )
|
|
{
|
|
if ( d4->dataFile->userCount > 1 ) /* already open, just set up tags */
|
|
{
|
|
u4namePiece( nameBuf, sizeof( nameBuf ), name, 0, 0 ) ;
|
|
if ( i4setup( c4, d4, nameBuf, 1 ) < 0 )
|
|
return -1 ;
|
|
}
|
|
else
|
|
{
|
|
#ifdef S4SERVER
|
|
/* if a temp file, tags already available... */
|
|
if ( d4->dataFile->file.isTemp == 1 )
|
|
{
|
|
if ( i4setup( c4, d4, nameBuf, 1 ) < 0 )
|
|
return -1 ;
|
|
}
|
|
#endif
|
|
i4 = i4open( d4, 0 ) ;
|
|
#ifdef S4SERVER
|
|
if ( i4 == 0 ) /* server version, if no .cgp file then don't open index */
|
|
error4set( c4, 0 ) ;
|
|
#else
|
|
if ( i4 == 0 )
|
|
return -1 ;
|
|
#endif
|
|
}
|
|
}
|
|
#else
|
|
#ifdef S4STAND_ALONE
|
|
d4->dataFile->openMdx = 0 ;
|
|
#endif
|
|
if ( ( d4->dataFile->hasMdxMemo & 0x01 ) && c4->autoOpen )
|
|
{
|
|
#ifndef S4SERVER
|
|
oldSingleOpen = c4->singleOpen ;
|
|
c4->singleOpen = OPEN4SPECIAL ;
|
|
#endif
|
|
i4 = i4open( d4, 0 ) ;
|
|
#ifndef S4SERVER
|
|
c4->singleOpen = oldSingleOpen ;
|
|
#endif
|
|
if ( i4 == 0 )
|
|
return -1 ;
|
|
#ifdef S4MDX
|
|
if ( !i4->indexFile->header.isProduction )
|
|
i4close( i4 ) ;
|
|
#endif
|
|
#ifdef S4STAND_ALONE
|
|
d4->dataFile->openMdx = 1 ;
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif /* S4CLIENT */
|
|
#endif /* S4OFF_INDEX */
|
|
|
|
#ifndef S4SERVER
|
|
c4->clientDataCount++ ;
|
|
d4->clientId = c4->clientDataCount ;
|
|
#endif
|
|
#ifndef S4OFF_WRITE
|
|
#ifndef S4OFF_TRAN
|
|
#ifndef S4CLIENT
|
|
if ( code4transEnabled( c4 ) )
|
|
{
|
|
trans = code4trans( c4 ) ;
|
|
#ifdef S4STAND_ALONE
|
|
connectionId = 0L ;
|
|
#else
|
|
connectionId = connection4id( c4->currentClient->connection ) ;
|
|
#endif
|
|
rc = u4nameCurrent( nameBuf, sizeof( nameBuf ), dfile4name( d4->dataFile ) ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( c4, rc, E94301 ) ;
|
|
#ifdef S4CASE_SEN
|
|
rc = u4nameExt( nameBuf, sizeof( nameBuf ), "dbf", 0 ) ;
|
|
#else
|
|
rc = u4nameExt( nameBuf, sizeof( nameBuf ), "DBF", 0 ) ;
|
|
#endif
|
|
if ( rc < 0 )
|
|
return error4stack( c4, rc, E94301 ) ;
|
|
rc = strlen(nameBuf) ;
|
|
if (c4->createTemp == 1)
|
|
tranCode = TRAN4OPEN_TEMP ;
|
|
else
|
|
tranCode = TRAN4OPEN ;
|
|
if ( tran4set( trans, trans->currentTranStatus, -1L, connectionId, tranCode,
|
|
(unsigned)rc + 19, data4clientId( d4 ), data4serverId( d4 ) ) == 0 )
|
|
{
|
|
tran4putData( trans, &rc, 2 ) ;
|
|
tran4putData( trans, nameBuf, (unsigned)rc ) ;
|
|
rcl = recWidth ;
|
|
tran4putData( trans, &rcl, 4 ) ;
|
|
rc = d4numFields( d4 ) ;
|
|
tran4putData( trans, &rc, 2 ) ;
|
|
rcl = d4recCount( d4 ) ;
|
|
tran4putData( trans, &rcl, 4 ) ;
|
|
/* */
|
|
if ( stat( nameBuf, &bufStat ) != 0 )
|
|
return -1 ;
|
|
tran4putData( trans, &bufStat.st_atime, 4 ) ;
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
tran4putData( trans, &d4->dataFile->yy, 3 ) ;
|
|
tran4lowAppend( trans, 0 ) ;
|
|
}
|
|
else
|
|
return -1 ;
|
|
}
|
|
#endif /* S4CLIENT */
|
|
#endif /* S4OFF_TRAN */
|
|
#endif /* S4OFF_WRITE */
|
|
|
|
#ifdef S4SERVER
|
|
d4->accessMode = c4->singleClient ;
|
|
if ( d4->accessMode == OPEN4DENY_RW )
|
|
d4->dataFile->exclusiveOpen = d4 ;
|
|
#endif
|
|
|
|
#ifndef S4CLIENT
|
|
d4->readOnly = c4->readOnly ;
|
|
#endif
|
|
|
|
#ifndef S4OFF_TRAN
|
|
#ifndef S4CLIENT
|
|
if ( code4transEnabled( d4->codeBase ) == 1 )
|
|
d4->logVal = c4->log ;
|
|
#endif
|
|
#endif
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
DATA4 *S4FUNCTION d4open( CODE4 *c4, const char *name )
|
|
{
|
|
int rc ;
|
|
char *info ;
|
|
DATA4 *d4 ;
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( c4 == 0 || name == 0 )
|
|
{
|
|
error4( 0, e4parm_null, E94301 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
d4 = d4openInit( c4 ) ;
|
|
if ( d4 != 0 )
|
|
{
|
|
d4->dataFile = dfile4open( c4, d4, name, &info ) ;
|
|
if ( d4->dataFile == 0 )
|
|
{
|
|
d4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
rc = d4openConclude( d4, name, info ) ;
|
|
if ( rc < 0 )
|
|
{
|
|
d4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
return d4 ;
|
|
}
|
|
|
|
DATA4 *S4FUNCTION d4openClone( DATA4 *dataOld )
|
|
{
|
|
DATA4 *d4 ;
|
|
int rc ;
|
|
char *info ;
|
|
#ifndef S4SERVER
|
|
int oldSingleOpen ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( dataOld == 0 )
|
|
{
|
|
error4( 0, e4parm_null, E94301 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
d4 = d4openInit( dataOld->codeBase ) ;
|
|
if ( d4 == 0 )
|
|
return 0 ;
|
|
#ifndef S4SERVER
|
|
oldSingleOpen = dataOld->codeBase->singleOpen ;
|
|
dataOld->codeBase->singleOpen = OPEN4DENY_NONE ;
|
|
#endif
|
|
d4->dataFile = data4reopen( dataOld->dataFile, &info ) ;
|
|
if ( d4->dataFile == 0 )
|
|
{
|
|
#ifndef S4SERVER
|
|
dataOld->codeBase->singleOpen = oldSingleOpen ;
|
|
#endif
|
|
d4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
rc = d4openConclude( d4, dfile4name( d4->dataFile ), info ) ;
|
|
#ifndef S4SERVER
|
|
dataOld->codeBase->singleOpen = oldSingleOpen ;
|
|
#endif
|
|
if ( rc < 0 )
|
|
{
|
|
d4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
return d4 ;
|
|
}
|
|
|
|
#ifndef S4OFF_INDEX
|
|
#ifdef S4CLIENT
|
|
int client4indexSetup( CODE4 *c4, DATA4 *d4, DATA4FILE *data, unsigned int numTags, const char *info, unsigned int iLen, const char *indexAlias, INDEX4 *i4ndx )
|
|
{
|
|
unsigned int i ;
|
|
TAG4FILE *tag, *first ;
|
|
INDEX4FILE *i4file ;
|
|
long infoLen ;
|
|
DATA4FILE *oldDataFile ;
|
|
int doTags ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( c4 == 0 || d4 == 0 || data == 0 || info == 0 )
|
|
return error4( c4, e4parm_null, E94302 ) ;
|
|
#endif
|
|
|
|
infoLen = iLen ;
|
|
|
|
if ( numTags == 0 )
|
|
return 0 ;
|
|
|
|
if ( c4->index4fileMemory == 0 )
|
|
{
|
|
c4->index4fileMemory = mem4create( c4, c4->memStartIndexFile, sizeof(INDEX4FILE), c4->memExpandIndexFile, 0 ) ;
|
|
if ( c4->index4fileMemory == 0 )
|
|
return e4memory ;
|
|
}
|
|
|
|
if ( c4->tagFileMemory == 0 )
|
|
{
|
|
c4->tagFileMemory = mem4create( c4, c4->memStartTagFile, sizeof(TAG4FILE), c4->memExpandTagFile, 0 ) ;
|
|
if ( c4->tagFileMemory == 0 )
|
|
return e4memory ;
|
|
}
|
|
|
|
oldDataFile = d4->dataFile ; ;
|
|
d4->dataFile = data ;
|
|
/* passing non-null into index4open will ensure that an actual open
|
|
does not occur, but simply a check will occur ... */
|
|
if ( i4ndx != 0 )
|
|
i4file = i4ndx->indexFile ;
|
|
else
|
|
i4file = index4open( d4, indexAlias, (INDEX4 *)1 ) ;
|
|
if ( i4file == 0 )
|
|
{
|
|
i4file = (INDEX4FILE *)mem4alloc( c4->index4fileMemory ) ;
|
|
if ( i4file == 0 )
|
|
{
|
|
d4->dataFile = oldDataFile ;
|
|
return error4stack( c4, e4memory, E94302 ) ;
|
|
}
|
|
|
|
i4file->codeBase = c4 ;
|
|
i4file->autoOpened = 1 ;
|
|
i4file->dataFile = data ;
|
|
i4file->clientId = data4clientId( d4 ) ;
|
|
i4file->serverId = data4serverId( d4 ) ;
|
|
d4->dataFile = oldDataFile ;
|
|
|
|
#ifdef E4MISC
|
|
if ( strlen( indexAlias ) > sizeof( i4file->accessName ) )
|
|
return error4describe( c4, e4name, E91102, indexAlias, 0, 0 ) ;
|
|
#endif
|
|
strcpy( i4file->accessName, indexAlias ) ;
|
|
c4upper( i4file->accessName ) ;
|
|
|
|
l4add( &data->indexes, i4file ) ;
|
|
doTags = 1 ;
|
|
}
|
|
else
|
|
doTags = 0 ;
|
|
|
|
/* only execute next if i4file was not blank and i4ndx was blank */
|
|
if ( i4ndx != 0 || doTags == 1 ) /* new index file, or add to existing */
|
|
{
|
|
for ( i = 0 ; i < numTags ; i++ )
|
|
{
|
|
tag = (TAG4FILE *)mem4alloc( c4->tagFileMemory ) ;
|
|
if ( tag == 0 )
|
|
return e4memory ;
|
|
infoLen -= LEN4TAG_ALIAS ;
|
|
if ( infoLen < 0 )
|
|
return e4connection ;
|
|
memcpy( tag->alias, info, LEN4TAG_ALIAS ) ;
|
|
tag->indexFile = i4file ;
|
|
info += LEN4TAG_ALIAS ;
|
|
tag->errUniqueHold = *(int *)info ;
|
|
info += sizeof( short int ) ;
|
|
first = (TAG4FILE *)l4first( &i4file->tags ) ;
|
|
if ( first == 0 )
|
|
l4add( &i4file->tags, tag ) ;
|
|
else
|
|
l4addBefore( &i4file->tags, first, tag ) ;
|
|
}
|
|
}
|
|
else
|
|
d4->dataFile = oldDataFile ;
|
|
return 0 ;
|
|
}
|
|
#endif /* S4CLIENT */
|
|
#endif /* not S4OFF_INDEX */
|
|
|
|
#ifdef S4SERVER
|
|
/* what is the maximal read and access setting on the data file */
|
|
/* does not report results for current client */
|
|
static void dfile4accesses( DATA4FILE *d4, int *readMode, int *accessMode, int *otherUsers )
|
|
{
|
|
SERVER4CLIENT *client ;
|
|
DATA4 *data ;
|
|
|
|
*readMode = 1 ;
|
|
*accessMode = OPEN4DENY_NONE ;
|
|
*otherUsers = 0 ;
|
|
|
|
for ( client = 0 ;; )
|
|
{
|
|
client = (SERVER4CLIENT *)l4next( &d4->c4->server->clients, client ) ;
|
|
if ( client == 0 )
|
|
break ;
|
|
if ( client == d4->c4->currentClient )
|
|
continue ;
|
|
for ( data = 0 ;; )
|
|
{
|
|
data = (DATA4 *)l4next( tran4dataList( &client->trans ), data ) ;
|
|
if ( data == 0 )
|
|
break ;
|
|
if ( data->dataFile == d4 )
|
|
{
|
|
*otherUsers = 1 ;
|
|
if ( data->readOnly == 0 )
|
|
*readMode = 0 ;
|
|
if ( *accessMode != OPEN4DENY_RW)
|
|
if ( data->accessMode != *accessMode )
|
|
if ( data->accessMode != OPEN4DENY_NONE )
|
|
*accessMode = data->accessMode ;
|
|
if ( *readMode == 0 && *accessMode == OPEN4DENY_RW ) /* maximal already */
|
|
return ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/* returns 1 if file can be accessed in desired mode */
|
|
static int dfile4checkAccess( DATA4FILE *d4, int accessRequested, int readOnly )
|
|
{
|
|
int maxAccess, maxRead, otherUsers ;
|
|
|
|
if ( d4->userCount == 0 )
|
|
return 1 ;
|
|
|
|
/* first get maximal access and read modes of other users */
|
|
dfile4accesses( d4, &maxRead, &maxAccess, &otherUsers ) ;
|
|
|
|
if ( otherUsers == 0 ) /* no other users, so any requests are ok */
|
|
return 1 ;
|
|
|
|
if ( accessRequested == OPEN4DENY_RW ) /* others users accessing, so no */
|
|
return 0 ;
|
|
|
|
if ( maxAccess == OPEN4DENY_RW ) /* other user is disallowing our access */
|
|
return 0 ;
|
|
|
|
if ( readOnly == 0 ) /* need write access */
|
|
{
|
|
if ( maxAccess != OPEN4DENY_NONE )
|
|
return 0 ;
|
|
/* maxAccess is DENY_NONE, so continue */
|
|
switch( accessRequested )
|
|
{
|
|
case OPEN4DENY_NONE:
|
|
return 1 ;
|
|
case OPEN4DENY_WRITE:
|
|
if ( maxRead == 1 ) /* others only reading, so ok */
|
|
return 1 ;
|
|
/* fall through, and any other case, access denied */
|
|
default:
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
/* is readOnly, so deny_write allowable by others */
|
|
switch( maxAccess )
|
|
{
|
|
case OPEN4DENY_RW:
|
|
return 0 ;
|
|
case OPEN4DENY_WRITE:
|
|
switch ( accessRequested )
|
|
{
|
|
case OPEN4DENY_NONE:
|
|
return 1 ;
|
|
case OPEN4DENY_WRITE:
|
|
if ( maxRead == 1 )
|
|
return 1 ;
|
|
/* fall through or default, no access */
|
|
default:
|
|
return 0 ;
|
|
}
|
|
default:
|
|
break ;
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
#endif /* S4SERVER */
|
|
|
|
static DATA4FILE *data4reopen( DATA4FILE *d4, char **info )
|
|
{
|
|
#ifndef S4CLIENT
|
|
#ifndef S4OFF_MULTI
|
|
int rc ;
|
|
#ifndef S4OFF_INDEX
|
|
#ifdef S4CLIPPER
|
|
TAG4FILE *t4file ;
|
|
#else
|
|
INDEX4FILE *i4file ;
|
|
#ifdef E4ANALYZE
|
|
#ifndef S4CLIPPER
|
|
unsigned short int nCheck ;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#ifndef S4SERVER
|
|
#ifndef S4OFF_TRAN
|
|
DATA4 *data4 ;
|
|
LIST4 *list ;
|
|
#endif
|
|
#endif
|
|
CODE4 *c4 ;
|
|
|
|
if ( d4 == 0 )
|
|
return 0 ;
|
|
|
|
c4 = d4->c4 ;
|
|
#ifndef S4CLIENT
|
|
if ( d4->userCount == 0 )
|
|
{
|
|
#ifndef S4OFF_MULTI
|
|
if ( d4->file.lowAccessMode != c4->accessMode ) /* need to open in updated mode */
|
|
{
|
|
rc = dfile4closeLow( d4 ) ;
|
|
if ( rc != 0 )
|
|
return 0 ;
|
|
#ifndef S4OFF_INDEX
|
|
#ifdef S4CLIPPER
|
|
for ( t4file = 0 ;; )
|
|
{
|
|
t4file = (TAG4FILE *)l4next( &d4->tagfiles, t4file ) ;
|
|
if ( t4file == 0 )
|
|
break ;
|
|
rc = tfile4close( t4file, d4 ) ;
|
|
if ( rc < 0 )
|
|
return 0 ;
|
|
}
|
|
#else
|
|
if ( d4->indexes.nLink != ((unsigned int)d4->hasMdxMemo & 0x01 ) )
|
|
{
|
|
for ( i4file = 0 ;; )
|
|
{
|
|
i4file = (INDEX4FILE *)l4next( &d4->indexes, i4file ) ;
|
|
if ( i4file == 0 )
|
|
break ;
|
|
if ( index4isProduction( i4file ) == 1 )
|
|
continue ;
|
|
#ifdef E4ANALYZE
|
|
nCheck = d4->indexes.nLink ;
|
|
#endif
|
|
rc = index4close( i4file ) ;
|
|
#ifdef E4ANALYZE
|
|
if ( nCheck != d4->indexes.nLink + 1 )
|
|
{
|
|
error4describe( c4, e4result, E91102, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
if ( rc < 0 )
|
|
return 0 ;
|
|
}
|
|
}
|
|
#endif /* S4CLIPPER */
|
|
#endif /* S4OFF_INDEX */
|
|
d4 = 0 ;
|
|
}
|
|
#endif /* S4OFF_MULTI */
|
|
}
|
|
else
|
|
{
|
|
#endif /* S4CLIENT */
|
|
#ifndef S4SERVER
|
|
if ( c4->singleOpen != OPEN4DENY_NONE ) /* only one instance allowed... */
|
|
{
|
|
#ifndef S4SERVER
|
|
#ifndef S4OFF_TRAN
|
|
/* verify that data4 not on the closed data list if within a
|
|
transaction (which is allowed) */
|
|
if ( code4tranStatus( c4 ) == r4active )
|
|
{
|
|
list = tran4dataList( code4trans( c4 ) ) ;
|
|
for ( data4 = 0 ;; )
|
|
{
|
|
data4 = (DATA4 *)l4next( list, data4 ) ;
|
|
if ( data4 == 0 )
|
|
break ;
|
|
if ( data4->dataFile == d4 )
|
|
{
|
|
error4describe( c4, e4instance, E91102, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
#ifdef E4ANALYZE
|
|
/* ensure that the datafile exists somewhere! */
|
|
list = &( code4trans( c4 )->closedDataFiles ) ;
|
|
for ( data4 = 0 ;; )
|
|
{
|
|
data4 = (DATA4 *)l4next( list, data4 ) ;
|
|
if ( data4 == 0 )
|
|
{
|
|
error4describe( c4, e4struct, E91102, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
if ( data4->dataFile == d4 )
|
|
break ;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
#endif /* S4OFF_TRAN */
|
|
#endif /* S4STAND_ALONE */
|
|
{
|
|
error4describe( c4, e4instance, E91102, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef E4ANALYZE
|
|
if ( d4->info == 0 )
|
|
{
|
|
error4describe( c4, e4struct, E91102, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
/* verify that the desired access level is available in terms of the actual physical open */
|
|
#ifndef S4OFF_MULTI
|
|
switch( c4->accessMode )
|
|
{
|
|
case OPEN4DENY_NONE:
|
|
break ;
|
|
case OPEN4DENY_RW:
|
|
#ifdef S4CLIENT
|
|
if ( d4->accessMode != OPEN4DENY_RW )
|
|
#else
|
|
if ( d4->file.lowAccessMode != OPEN4DENY_RW )
|
|
#endif
|
|
{
|
|
error4describe( c4, e4access, E84307, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
break ;
|
|
case OPEN4DENY_WRITE:
|
|
#ifdef S4CLIENT
|
|
if ( d4->accessMode == OPEN4DENY_NONE )
|
|
#else
|
|
if ( d4->file.lowAccessMode == OPEN4DENY_NONE )
|
|
#endif
|
|
{
|
|
error4describe( c4, e4access, E84307, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
break ;
|
|
default:
|
|
{
|
|
error4describe( c4, e4access, E82502, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
#endif /* S4OFF_MULTI */
|
|
|
|
#ifdef S4SERVER
|
|
/* singleClient is the client's requested access mode */
|
|
if ( d4 != 0 )
|
|
if ( dfile4checkAccess( d4, c4->singleClient, c4->readOnly ) == 0 ) /* access denied */
|
|
{
|
|
error4describe( c4, e4access, E91102, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
#ifndef S4CLIENT
|
|
}
|
|
#endif
|
|
|
|
if ( d4 != 0 )
|
|
{
|
|
d4->userCount++ ;
|
|
*info = d4->info ;
|
|
#ifdef E4ANALYZE
|
|
if ( d4->nFields == 0 )
|
|
{
|
|
error4describe( c4, e4struct, E91102, dfile4name( d4 ), 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
return d4 ;
|
|
}
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
#ifdef P4ARGS_USED
|
|
#pragma argsused
|
|
#endif
|
|
DATA4FILE *dfile4open( CODE4 *c4, DATA4 *data, const char *name, char **info )
|
|
{
|
|
int rc ;
|
|
DATA4FILE *d4 ;
|
|
unsigned int count ;
|
|
int iFields ;
|
|
FIELD4IMAGE *image ;
|
|
#ifdef S4CLIENT
|
|
SOCKET4 *socket ;
|
|
CONNECTION4 *connection ;
|
|
int len2, len3 ;
|
|
CONNECTION4OPEN_INFO_IN dataIn ;
|
|
CONNECTION4OPEN_INFO_OUT *dataInfo ;
|
|
#ifndef S4OFF_INDEX
|
|
char indexName[258] ;
|
|
#endif
|
|
#else
|
|
char nameBuf[258] ;
|
|
DATA4HEADER_FULL fullHeader ;
|
|
unsigned fieldDataLen ;
|
|
#ifndef S4OFF_MEMO
|
|
int hasMemo ;
|
|
#endif
|
|
#ifndef S4OFF_CATALOG
|
|
int i ;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef S4VBASIC
|
|
if ( c4parm_check( c4, 1, E91102 ) )
|
|
return 0 ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( c4 == 0 || name == 0 )
|
|
{
|
|
error4( c4, e4parm_null, E91102 ) ;
|
|
return 0 ;
|
|
}
|
|
#ifdef S4CLIENT
|
|
if ( data == 0 )
|
|
{
|
|
error4( c4, e4parm_null, E91102 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
if ( error4code( c4 ) < 0 )
|
|
return 0 ;
|
|
|
|
#ifdef E4ANALYZE
|
|
if ( c4->debugInt != 0x5281 )
|
|
{
|
|
error4( 0, e4result, E81301 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
#ifdef S4CLIENT
|
|
d4 = dfile4data( c4, name ) ;
|
|
#else
|
|
u4nameCurrent( nameBuf, sizeof( nameBuf ), name ) ;
|
|
u4nameExt( nameBuf, sizeof(nameBuf), "dbf", 0 ) ;
|
|
#ifndef S4CASE_SEN /* preserve the case sensitivity for unix */
|
|
c4upper( nameBuf ) ;
|
|
#endif
|
|
d4 = dfile4data( c4, nameBuf ) ;
|
|
#endif
|
|
|
|
if ( d4 != 0 )
|
|
{
|
|
d4 = data4reopen( d4, info ) ;
|
|
if ( error4code( c4 ) < 0 )
|
|
return 0 ;
|
|
if ( d4 != 0 )
|
|
return d4 ;
|
|
}
|
|
|
|
#ifdef S4CLIENT
|
|
#ifdef E4MISC
|
|
if ( strlen( name ) > LEN4PATH )
|
|
{
|
|
error4describe( c4, e4name, E84301, name, 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
if ( c4->defaultServer == 0 )
|
|
{
|
|
rc = code4connect( c4, 0, DEF4PROCESS_ID, 0, 0, 0 ) ;
|
|
if ( rc == 0 )
|
|
{
|
|
if ( c4->defaultServer == 0 )
|
|
{
|
|
error4describe( c4, e4connection, E84302, DEF4SERVER_ID, DEF4PROCESS_ID, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
rc = code4dateFormatSet( c4, code4dateFormat( c4 ) ) ;
|
|
}
|
|
if ( rc != 0 )
|
|
{
|
|
if ( c4->defaultServer != 0 )
|
|
{
|
|
socket4initUndo( c4->defaultServer ) ;
|
|
socket4free( c4->defaultServer ) ;
|
|
c4->defaultServer = 0 ;
|
|
}
|
|
error4describe( c4, e4connection, E81001, DEF4SERVER_ID, DEF4PROCESS_ID, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
socket = c4->defaultServer ;
|
|
memset( &dataIn, 0, sizeof( CONNECTION4OPEN_INFO_IN ) ) ;
|
|
if ( socket == 0 )
|
|
{
|
|
error4( c4, e4connection, E84303 ) ;
|
|
return 0 ;
|
|
}
|
|
connection = socket->connect ;
|
|
if ( connection == 0 )
|
|
{
|
|
error4( c4, e4connection, E84303 ) ;
|
|
return 0 ;
|
|
}
|
|
connection4assign( connection, CON4OPEN, data->trans->dataIdCount,0 ) ;
|
|
data->trans->dataIdCount++ ;
|
|
|
|
len3 = strlen( name ) + 1 ;
|
|
if ( len3 > LEN4PATH )
|
|
len3 = LEN4PATH ;
|
|
|
|
memcpy( dataIn.name, name, len3 ) ;
|
|
dataIn.name[LEN4PATH] = 0 ;
|
|
|
|
#ifdef S4OFF_MULTI
|
|
dataIn.exclusiveClient = 1 ;
|
|
#else
|
|
dataIn.accessMode = c4->accessMode ;
|
|
#endif
|
|
|
|
dataIn.readOnly = c4->readOnly ;
|
|
dataIn.safety = c4->safety ; /* for catalog */
|
|
dataIn.errDefaultUnique = c4->errDefaultUnique ;
|
|
dataIn.openForCreate = c4->openForCreate ;
|
|
dataIn.singleOpen = c4->singleOpen ;
|
|
dataIn.log = c4->log ;
|
|
|
|
connection4addData( connection, &dataIn, sizeof( CONNECTION4OPEN_INFO_IN ), 0 ) ;
|
|
connection4send( connection ) ;
|
|
rc = connection4receive( connection ) ;
|
|
if ( rc < 0 )
|
|
{
|
|
error4( c4, rc, E91102 ) ;
|
|
return 0 ;
|
|
}
|
|
if ( connection4type( connection ) != CON4OPEN )
|
|
{
|
|
error4( c4, e4connection, E84304 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
rc = connection4status( connection ) ;
|
|
if ( rc < 0 )
|
|
{
|
|
if ( c4->errOpen == 0 )
|
|
error4set( c4, r4noOpen ) ;
|
|
else
|
|
connection4errorDescribe( connection, c4, rc, E91102, name, 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
if ( connection4len( connection ) < sizeof( CONNECTION4OPEN_INFO_OUT ) )
|
|
{
|
|
error4( c4, e4connection, E84305 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
dataInfo = (CONNECTION4OPEN_INFO_OUT *)connection4data( connection ) ;
|
|
#endif /* S4CLIENT */
|
|
|
|
if ( c4->data4fileMemory == 0 )
|
|
{
|
|
c4->data4fileMemory = mem4create( c4, c4->memStartDataFile, sizeof(DATA4FILE), c4->memExpandDataFile, 0 ) ;
|
|
if ( c4->data4fileMemory == 0 )
|
|
{
|
|
error4( c4, e4memory, E91102 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
d4 = (DATA4FILE *)mem4alloc( c4->data4fileMemory ) ;
|
|
if ( d4 == 0 )
|
|
{
|
|
error4( c4, e4memory, E91102 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
d4->c4 = c4 ;
|
|
d4->userCount = 1 ;
|
|
|
|
#ifndef S4CLIENT
|
|
#ifndef S4OFF_MEMO
|
|
d4->memoFile.file.hand = -1 ;
|
|
#endif
|
|
|
|
#ifdef S4SERVER
|
|
#ifndef S4OFF_CATALOG
|
|
if ( cat4avail( c4->catalog ) )
|
|
{
|
|
u4ncpy( nameBuf, cat4pathName( c4->catalog ), (unsigned int)cat4pathNameLen( c4->catalog ) ) ;
|
|
for ( i = 0 ; i < cat4pathNameLen( c4->catalog ) ; i++ )
|
|
if ( nameBuf[i] == ' ' )
|
|
{
|
|
nameBuf[i] = 0 ;
|
|
break ;
|
|
}
|
|
|
|
}
|
|
#endif /* S4OFF_CATALOG */
|
|
#endif /* S4SERVER */
|
|
rc = file4open( &d4->file, c4, nameBuf, 1 ) ;
|
|
|
|
if ( rc )
|
|
{
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
l4add( &c4->dataFileList, &d4->link ) ;
|
|
|
|
#ifdef S4CLIENT
|
|
#ifdef E4MISC
|
|
if ( strlen( name ) > sizeof( d4->accessName ) )
|
|
{
|
|
error4describe( c4, e4name, E91102, name, 0, 0 ) ;
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
strcpy( d4->accessName, name ) ;
|
|
c4upper( d4->accessName ) ;
|
|
d4->connection = connection ;
|
|
d4->recWidth = dataInfo->recWidth ;
|
|
d4->headerLen = dataInfo->headerLen ;
|
|
d4->version = dataInfo->version ;
|
|
d4->serverId = dataInfo->serverId ;
|
|
data->readOnly = dataInfo->readOnly ;
|
|
|
|
d4->info = (char *)u4allocFree( c4, dataInfo->infoLen ) ;
|
|
if ( d4->info == 0 )
|
|
{
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
len2 = sizeof( CONNECTION4OPEN_INFO_OUT ) ;
|
|
memcpy( d4->info, connection4data( connection ) + len2, dataInfo->infoLen ) ;
|
|
d4->infoLen = dataInfo->infoLen ;
|
|
len2 += dataInfo->infoLen ;
|
|
|
|
#ifndef S4OFF_INDEX
|
|
/* index file information... */
|
|
if ( c4->autoOpen == 1 && dataInfo->numTags > 0 )
|
|
{
|
|
u4namePiece( indexName, sizeof(indexName), name, 1, 0 ) ;
|
|
rc = client4indexSetup( c4, data, d4, dataInfo->numTags, connection4data( connection ) + len2, (unsigned int)connection4len( connection ) - len2, indexName, 0 ) ;
|
|
if ( rc < 0 )
|
|
{
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
#endif
|
|
#else
|
|
if ( file4readAll( &d4->file, 0L, &fullHeader, sizeof( fullHeader ) ) < 0 )
|
|
{
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
#ifdef S4BYTE_SWAP
|
|
fullHeader.numRecs = x4reverseLong( (void *)&fullHeader.numRecs ) ;
|
|
fullHeader.headerLen = x4reverseShort( (void *)&fullHeader.headerLen ) ;
|
|
fullHeader.recordLen = x4reverseShort( (void *)&fullHeader.recordLen ) ;
|
|
#endif
|
|
|
|
#ifdef S4DEMO
|
|
if ( fullHeader.numRecs > 200L)
|
|
{
|
|
error4( c4, e4demo, 0 ) ;
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
if ( fullHeader.recordLen == 0 ) /* divide by zero */
|
|
{
|
|
error4describe( c4, e4data, E83805, nameBuf, dfile4name( d4 ), (char *)0 ) ;
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
#ifndef S4CLIENT
|
|
/* if the file is opened deny write/exclusively, and this was the first open, then
|
|
verify that the record count matches the file length (i.e. to avoid
|
|
data file corruption) */
|
|
if ( c4->accessMode == OPEN4DENY_WRITE || c4->accessMode == OPEN4DENY_RW )
|
|
if ( fullHeader.numRecs != ( file4len( &d4->file ) - fullHeader.headerLen ) / fullHeader.recordLen )
|
|
{
|
|
error4describe( c4, e4data, E83805, nameBuf, dfile4name( d4 ), (char *)0 ) ;
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
if ( fullHeader.numRecs < 0L || fullHeader.numRecs > ( 1 + ( file4len ( &d4->file ) - fullHeader.headerLen ) / fullHeader.recordLen ) )
|
|
{
|
|
error4describe( c4, e4data, E83805, nameBuf, dfile4name( d4 ), (char *)0 ) ;
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
memcpy( (void *)&d4->version, (void *)&fullHeader.version, (4+(sizeof(S4LONG))+(sizeof(short))) ) ;
|
|
|
|
#ifdef S4FOX
|
|
data->codePage = fullHeader.codePage ;
|
|
#endif
|
|
|
|
d4->hasMdxMemo = fullHeader.hasMdxMemo ;
|
|
|
|
fieldDataLen = fullHeader.headerLen-sizeof(fullHeader) ;
|
|
if ( fullHeader.headerLen <= sizeof(fullHeader) )
|
|
{
|
|
error4describe( c4, e4data, E83805, nameBuf, dfile4name( d4 ), (char *)0 ) ;
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
d4->info = (char *)u4allocFree( c4, (long)fieldDataLen ) ;
|
|
d4->infoLen = fieldDataLen ;
|
|
d4->headerLen = fullHeader.headerLen ;
|
|
if ( d4->info == 0 )
|
|
{
|
|
#ifdef E4STACK
|
|
error4stack( c4, e4memory, E91102 ) ;
|
|
#endif
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
/* 06/18/96 AS --> fullHeader not read in prior place, must be after previous read */
|
|
#ifndef S4OFF_OPTIMIZE
|
|
file4optimizeLow( &d4->file, c4->optimize, OPT4DBF, fullHeader.recordLen, d4 ) ;
|
|
#endif
|
|
|
|
if ( file4readAll( &d4->file, (long)sizeof(fullHeader), d4->info, fieldDataLen ) < 0 )
|
|
{
|
|
error4describe( c4, e4data, E84306, name, 0, 0 ) ;
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
if ( error4code( c4 ) < 0 )
|
|
{
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
#ifndef S4OFF_MEMO
|
|
if ( d4->version == 0x30 ) /* visual FP 3.0 */
|
|
hasMemo = fullHeader.hasMdxMemo & 0x02 ;
|
|
else
|
|
hasMemo = d4->version & 0x80 ;
|
|
if ( hasMemo )
|
|
{
|
|
#ifdef S4MFOX
|
|
#ifdef S4CASE_SEN
|
|
u4nameExt( nameBuf, sizeof(nameBuf), "fpt", 1 ) ;
|
|
#else
|
|
u4nameExt( nameBuf, sizeof(nameBuf), "FPT", 1 ) ;
|
|
#endif
|
|
#else
|
|
#ifdef S4CASE_SEN
|
|
u4nameExt( nameBuf, sizeof(nameBuf), "dbt", 1 ) ;
|
|
#else
|
|
u4nameExt( nameBuf, sizeof(nameBuf), "DBT", 1 ) ;
|
|
#endif
|
|
#endif
|
|
if ( memo4fileOpen( &d4->memoFile, d4, nameBuf ) < 0 )
|
|
{
|
|
dfile4close( d4 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
d4->numRecs = -1L ;
|
|
*info = d4->info ;
|
|
|
|
/* count the number of fields */
|
|
for ( count = 0 ; d4->info[count] != 0xD ; count += 32 ) ;
|
|
d4->nFields = (int)( count / 32 ) ;
|
|
|
|
#ifdef E4ANALYZE
|
|
if ( d4->nFields == 0 )
|
|
{
|
|
error4describe( c4, e4data, E84309, name, dfile4name( d4 ), 0 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
d4->recWidth = 1 ;
|
|
d4->nFieldsMemo = 0 ;
|
|
|
|
for ( iFields = 0; iFields < d4->nFields; iFields++ )
|
|
{
|
|
image = (FIELD4IMAGE *)(((char *)*info) + iFields * 32 ) ;
|
|
|
|
switch( image->type )
|
|
{
|
|
case r4memo:
|
|
case r4gen:
|
|
d4->nFieldsMemo++ ;
|
|
d4->recWidth += image->len ;
|
|
break ;
|
|
case r4num:
|
|
case r4float:
|
|
case r4log:
|
|
case r4date:
|
|
d4->recWidth += image->len ;
|
|
break ;
|
|
case r4str:
|
|
d4->recWidth += ( image->len + (image->dec << 8) ) ;
|
|
break ;
|
|
case r4double: /* r4bin and r4double the same */
|
|
if ( d4->version == 0x30 )
|
|
{
|
|
d4->recWidth += image->len ;
|
|
if ( d4->version != 0x30 ) /* 2.5 data files disallowed these fields */
|
|
{
|
|
dfile4close( d4 ) ;
|
|
#ifdef S4SERVER
|
|
error4describe( c4, e4data, E80501, nameBuf, dfile4name( d4 ), 0 ) ;
|
|
#else
|
|
error4describe( c4, e4data, E80501, name, dfile4name( d4 ), 0 ) ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
d4->nFieldsMemo++ ;
|
|
d4->recWidth += image->len ;
|
|
}
|
|
break ;
|
|
#ifdef S4CLIENT_OR_FOX
|
|
case r4currency:
|
|
case r4int:
|
|
case r4dateTime:
|
|
d4->recWidth += image->len ;
|
|
if ( d4->version != 0x30 ) /* 2.5 data files disallowed these fields */
|
|
{
|
|
dfile4close( d4 ) ;
|
|
#ifdef S4SERVER
|
|
error4describe( c4, e4data, E80501, nameBuf, dfile4name( d4 ), 0 ) ;
|
|
#else
|
|
error4describe( c4, e4data, E80501, name, dfile4name( d4 ), 0 ) ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
break ;
|
|
case r4system: /* null-fields/system field */
|
|
if ( ( d4->version != 0x30 ) || ( memcmp( image->name, "_NullFlags", 10 ) != 0 ) ) /* not visual FP 3.0 */
|
|
{
|
|
dfile4close( d4 ) ;
|
|
#ifdef S4SERVER
|
|
error4describe( c4, e4data, E80501, nameBuf, dfile4name( d4 ), 0 ) ;
|
|
#else
|
|
error4describe( c4, e4data, E80501, name, dfile4name( d4 ), 0 ) ;
|
|
#endif
|
|
}
|
|
d4->recWidth += image->len ;
|
|
break ;
|
|
#endif
|
|
default:
|
|
dfile4close( d4 ) ;
|
|
#ifdef S4SERVER
|
|
error4describe( c4, e4data, E80501, nameBuf, dfile4name( d4 ), 0 ) ;
|
|
#else
|
|
error4describe( c4, e4data, E80501, name, dfile4name( d4 ), 0 ) ;
|
|
#endif
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
#ifdef S4SERVER
|
|
if ( d4->recWidth != fullHeader.recordLen )
|
|
{
|
|
dfile4close( d4 ) ;
|
|
error4describe( c4, e4data, E91102, nameBuf, dfile4name( d4 ), 0 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
#ifdef S4CLIENT
|
|
d4->accessMode = c4->accessMode ;
|
|
#else
|
|
d4->valid = 1 ; /* valid, so low closes will leave open. */
|
|
#endif
|
|
|
|
return d4 ;
|
|
}
|
|
|
|
#ifdef S4VB_DOS
|
|
|
|
DATA4 * d4open_v( CODE4 *c4, char *name )
|
|
{
|
|
return d4open( c4, c4str(name) ) ;
|
|
}
|
|
|
|
#endif
|
|
|