Files correlati : cb6.dll Ricompilazione Demo : [ ] Commento : Modifiche per la compilazione Linux git-svn-id: svn://10.65.10.50/trunk@11080 c028cbd2-c16b-5b4b-a496-9718f37d4682
1484 lines
45 KiB
C
Executable File
1484 lines
45 KiB
C
Executable File
/* e4parse.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
|
|
|
|
/* Restrictions - STR can only have a constant 2nd & 3rd parameters
|
|
SUBSTR can only have a constant 2nd & 3rd parameters
|
|
LEFT can only have a constant 2nd parameter
|
|
RIGHT can only have a constant 2nd paramater, and the
|
|
first paramater must be a field or constant only.
|
|
IIF must return a predictable length and type
|
|
TRIM, LTRIM & ALLTRIM return unpredictable lengths.
|
|
Its result
|
|
Ex. TRIM(L_NAME) + TRIM(F_NAME) is OK
|
|
SUBSTR( TRIM(L_NAME), 3, 2 ) is not OK
|
|
Memo field's evaluate to a maximum length. Anything over
|
|
this maximum gets truncated.
|
|
*/
|
|
|
|
#include "d4all.h"
|
|
#ifdef __TURBOC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
|
|
static void e4functionPop( EXPR4 * ) ;
|
|
|
|
/* e4massage
|
|
- Check the type returns to ensure that functions get the correct type
|
|
result. Use 'E4FUNCTIONS.code' to change the function where possible
|
|
so that the correct function is used.
|
|
- Make sure that field parameters are put on the stack for the concatentate
|
|
operators.
|
|
- Fill in the function pointers.
|
|
- Change (FIELD4 *) pointers in 'p1' to (char *) pointers.
|
|
- Where the result stack is used, make sure the correct values are filled
|
|
into the E4INFO entires in order to adjust for the lengths needed.
|
|
- Check the length returns to make sure that 'codeBase->exprBufLen' is large enough
|
|
to handle executing the expression.
|
|
- Calculate the length of the final result.
|
|
- Enforce restrictions to TRIM, STR and IIF
|
|
- Make sure an extra max. length character is added for e4upper() & e4trim()
|
|
*/
|
|
|
|
static int e4massage( E4PARSE *p4 )
|
|
{
|
|
E4INFO *info ;
|
|
int parmPos, iParm, isOk, codeOn, iInfo, numParms ;
|
|
int typeShouldBe, len, lengthStatus, i, doneTrimMemoOrCalc ;
|
|
int position[E4MAX_STACK_ENTRIES+1] ;
|
|
long length[E4MAX_STACK_ENTRIES] ;
|
|
long bufLenNeeded ;
|
|
int types[E4MAX_STACK_ENTRIES] ;
|
|
int numEntries[E4MAX_STACK_ENTRIES] ;
|
|
E4INFO *pointers[E4MAX_STACK_ENTRIES] ;
|
|
CODE4 *codeBase ;
|
|
unsigned storedKeyLen ;
|
|
#ifdef S4DATA_ALIGN
|
|
int delta ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( p4 == 0 )
|
|
return error4( 0, e4parm_null, E90901 ) ;
|
|
#endif
|
|
|
|
#ifdef E4MISC
|
|
memset( types, 0, sizeof( types ) ) ;
|
|
memset( pointers, 0, sizeof( pointers ) ) ;
|
|
memset( length, 0, sizeof( length ) ) ;
|
|
memset( numEntries, 0, sizeof( numEntries ) ) ;
|
|
memset( position, 0, sizeof( position ) ) ;
|
|
#endif
|
|
|
|
codeBase = p4->codeBase ;
|
|
numParms = doneTrimMemoOrCalc = 0 ;
|
|
bufLenNeeded = 0 ;
|
|
|
|
position[0] = 0 ; /* The first parameter can be placed at position 0 */
|
|
|
|
for( iInfo = 0; iInfo < p4->expr.infoN; iInfo++ )
|
|
{
|
|
info = p4->expr.info + iInfo ;
|
|
|
|
/* Check the parameters types */
|
|
codeOn = v4functions[info->functionI].code ;
|
|
if ( v4functions[info->functionI].numParms != (char)info->numParms )
|
|
if ( v4functions[info->functionI].numParms > 0 )
|
|
{
|
|
if( codeBase->errExpr )
|
|
return error4describe( codeBase, e4numParms, E90901, p4->expr.source, 0, 0 ) ;
|
|
return e4numParms ;
|
|
}
|
|
|
|
for( ;; )
|
|
{
|
|
if ( codeOn != v4functions[info->functionI].code )
|
|
{
|
|
if( codeBase->errExpr )
|
|
return error4describe( codeBase, e4typeSub, E90901, p4->expr.source, 0, 0 ) ;
|
|
return e4typeSub ;
|
|
}
|
|
|
|
isOk = 1 ;
|
|
|
|
for( iParm = 0; iParm < info->numParms; iParm++ )
|
|
{
|
|
if ( (int)v4functions[info->functionI].numParms < 0 )
|
|
typeShouldBe = v4functions[info->functionI].type[0] ;
|
|
else
|
|
typeShouldBe = v4functions[info->functionI].type[iParm] ;
|
|
|
|
parmPos = numParms - info->numParms + iParm ;
|
|
|
|
if ( types[parmPos] != typeShouldBe )
|
|
{
|
|
if ( types[parmPos] == r4date && typeShouldBe == r4dateDoub )
|
|
{
|
|
pointers[parmPos]->functionI = E4FIELD_DATE_D ;
|
|
length[parmPos] = sizeof(double) ;
|
|
continue ;
|
|
}
|
|
if ( types[parmPos] == r4num && typeShouldBe == r4numDoub )
|
|
{
|
|
pointers[parmPos]->functionI = E4FIELD_NUM_D ;
|
|
length[parmPos] = sizeof(double) ;
|
|
continue ;
|
|
}
|
|
#ifdef S4CLIENT_OR_FOX
|
|
if ( types[parmPos] == r4int && typeShouldBe == r4numDoub )
|
|
{
|
|
pointers[parmPos]->functionI = E4FIELD_INT_D ;
|
|
length[parmPos] = sizeof(double) ;
|
|
continue ;
|
|
}
|
|
if ( types[parmPos] == r4currency && typeShouldBe == r4numDoub )
|
|
{
|
|
pointers[parmPos]->functionI = E4FIELD_CUR_D ;
|
|
length[parmPos] = sizeof(double) ;
|
|
continue ;
|
|
}
|
|
#endif
|
|
|
|
info->functionI++ ;
|
|
isOk = 0 ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( isOk )
|
|
break ;
|
|
}
|
|
|
|
switch( info->functionI )
|
|
{
|
|
case E4CONCATENATE:
|
|
case E4CONCAT_TWO:
|
|
case E4TRIM:
|
|
case E4LTRIM:
|
|
case E4ALLTRIM:
|
|
case E4UPPER:
|
|
case E4SUBSTR:
|
|
case E4LEFT:
|
|
case E4RIGHT:
|
|
case E4DESCEND:
|
|
case E4DESCEND+1:
|
|
case E4DESCEND+2:
|
|
case E4DESCEND+3:
|
|
case E4DESCEND+4:
|
|
case E4DESCEND+5:
|
|
case E4DESCEND+6:
|
|
case E4ASCEND:
|
|
case E4ASCEND+1:
|
|
case E4ASCEND+2:
|
|
case E4ASCEND+3:
|
|
case E4ASCEND+4:
|
|
case E4ASCEND+5:
|
|
case E4ASCEND+6:
|
|
#ifndef S4MEMO_OFF
|
|
case E4FIELD_MEMO:
|
|
#endif
|
|
for( iParm = 1; iParm <= info->numParms; iParm++ )
|
|
{
|
|
E4INFO *info_parm = pointers[numParms-iParm] ;
|
|
if ( info_parm->functionI == E4FIELD_STR )
|
|
/* Make sure the parameter is put on the stack. */
|
|
info_parm->functionI = E4FIELD_STR_CAT ;
|
|
if ( info->functionI == E4CONCATENATE && doneTrimMemoOrCalc )
|
|
info->functionI = E4CONCAT_TRIM ;
|
|
}
|
|
break ;
|
|
default:
|
|
break ;
|
|
}
|
|
|
|
numParms -= info->numParms ;
|
|
if ( numParms < 0 )
|
|
if( codeBase->errExpr )
|
|
return error4( codeBase, e4result, E90901 ) ;
|
|
|
|
types[numParms] = v4functions[info->functionI].returnType ;
|
|
|
|
if ( info->functionI == E4CALC_FUNCTION )
|
|
types[numParms] = expr4type( ((EXPR4CALC *) info->p1)->expr ) ;
|
|
switch( types[numParms] )
|
|
{
|
|
case r4str:
|
|
switch( info->functionI )
|
|
{
|
|
case E4FIELD_STR:
|
|
case E4FIELD_STR_CAT:
|
|
length[numParms] = f4len( info->fieldPtr ) ;
|
|
break ;
|
|
|
|
#ifndef S4MEMO_OFF
|
|
case E4FIELD_MEMO:
|
|
length[numParms] = codeBase->memSizeMemoExpr ;
|
|
doneTrimMemoOrCalc = 1 ;
|
|
break ;
|
|
#endif /* S4MEMO_OFF */
|
|
|
|
case E4CONCATENATE:
|
|
case E4CONCAT_TWO:
|
|
case E4CONCAT_TRIM:
|
|
info->i1 = (int) (length[numParms]) ;
|
|
length[numParms] += length[numParms+1] ;
|
|
break ;
|
|
|
|
case E4IIF:
|
|
if ( length[numParms+1] != length[numParms+2] )
|
|
if( codeBase->errExpr )
|
|
return error4describe( codeBase, e4lengthErr, E90901, p4->expr.source, 0, 0 ) ;
|
|
length[numParms] = length[numParms+1] ;
|
|
break ;
|
|
|
|
case E4DTOS:
|
|
case E4DTOS+1:
|
|
length[numParms] = sizeof(double) ;
|
|
break ;
|
|
|
|
case E4DTOC:
|
|
case E4DTOC+1:
|
|
case E4CTOD:
|
|
length[numParms] = sizeof(double) ;
|
|
info->i1 = p4->constants.pos ;
|
|
len = strlen( code4dateFormat( codeBase ) ) ;
|
|
s4stackPushStr( &p4->constants, code4dateFormat( codeBase ), len + 1 ) ;
|
|
if ( info->functionI == E4DTOC || info->functionI == E4DTOC+1 )
|
|
length[numParms] = len ;
|
|
break ;
|
|
|
|
case E4CHR:
|
|
length[numParms] = sizeof(char) ;
|
|
break ;
|
|
|
|
case E4DEL:
|
|
length[numParms] = sizeof(char) ;
|
|
#ifndef S4CLIENT
|
|
if ( p4->expr.tagPtr ) /* data4 independent, so point to datafile */
|
|
info->p1 = (char *)&p4->expr.dataFile->record ;
|
|
else /* data4 dependent, so just point to record */
|
|
#endif
|
|
info->p1 = (char *)&p4->expr.data->record ;
|
|
break ;
|
|
|
|
case E4CALC_FUNCTION:
|
|
doneTrimMemoOrCalc = 1 ;
|
|
length[numParms] = expr4len( ((EXPR4CALC *) info->p1)->expr ) ;
|
|
break ;
|
|
|
|
case E4RIGHT:
|
|
if ( info->i1 > (int)(length[numParms]) )
|
|
info->i1 = (int)(length[numParms]) ;
|
|
if ( info->i1 < 0 )
|
|
info->i1 = 0 ;
|
|
if ( info->len > (int)(length[numParms]) )
|
|
info->len = (int)(length[numParms]) ;
|
|
length[numParms] = info->len ;
|
|
break ;
|
|
case E4SUBSTR:
|
|
case E4LEFT:
|
|
if ( info->i1 > (int)(length[numParms]) )
|
|
info->i1 = (int)(length[numParms]) ;
|
|
if ( info->i1 < 0 )
|
|
info->i1 = 0 ;
|
|
length[numParms] -= info->i1 ;
|
|
if ( info->len > (int)(length[numParms]) )
|
|
info->len = (int)(length[numParms]) ;
|
|
length[numParms] = info->len ;
|
|
break ;
|
|
|
|
case E4TIME:
|
|
length[numParms] = sizeof(double) ;
|
|
break ;
|
|
|
|
case E4TRIM:
|
|
case E4LTRIM:
|
|
case E4ALLTRIM:
|
|
doneTrimMemoOrCalc = 1 ;
|
|
p4->expr.hasTrim = 1 ;
|
|
break ;
|
|
|
|
case E4UPPER:
|
|
break ;
|
|
case E4DESCEND:
|
|
case E4DESCEND+1:
|
|
case E4DESCEND+2:
|
|
case E4DESCEND+3:
|
|
case E4DESCEND+4:
|
|
#ifdef S4CLIENT_OR_FOX
|
|
case E4DESCEND+5:
|
|
case E4DESCEND+6:
|
|
#endif
|
|
case E4ASCEND:
|
|
case E4ASCEND+1:
|
|
case E4ASCEND+2:
|
|
case E4ASCEND+3:
|
|
case E4ASCEND+4:
|
|
#ifdef S4CLIENT_OR_FOX
|
|
case E4ASCEND+5:
|
|
case E4ASCEND+6:
|
|
#endif
|
|
if( types[numParms] == r4dateDoub || types[numParms] == r4numDoub ||
|
|
types[numParms] == r4dateTime )
|
|
length[numParms] = sizeof(double) ;
|
|
if( types[numParms] == r4log )
|
|
length[numParms] = sizeof(char) ;
|
|
break ;
|
|
default:
|
|
length[numParms] = info->len ;
|
|
}
|
|
break ;
|
|
|
|
case r4num:
|
|
length[numParms] = f4len( info->fieldPtr ) ;
|
|
break ;
|
|
|
|
#ifdef S4CLIENT_OR_FOX
|
|
case r4currency:
|
|
length[numParms] = sizeof(double) ;
|
|
break ;
|
|
case r4dateTime:
|
|
length[numParms] = sizeof(double) ;
|
|
break ;
|
|
case r4int:
|
|
length[numParms] = sizeof(long) ;
|
|
break ;
|
|
#endif
|
|
|
|
case r4numDoub:
|
|
case r4dateDoub:
|
|
length[numParms] = sizeof(double) ;
|
|
if ( info->functionI == E4CTOD )
|
|
{
|
|
info->i1 = p4->constants.pos ;
|
|
s4stackPushStr( &p4->constants, code4dateFormat( codeBase ), strlen( code4dateFormat( codeBase ) ) + 1 ) ;
|
|
}
|
|
if ( info->functionI == E4RECCOUNT )
|
|
info->p1 = (char *)p4->expr.dataFile ;
|
|
if ( info->functionI == E4RECNO )
|
|
info->p1 = 0 ; /* updated for c/s support, just use expr data4 */
|
|
break ;
|
|
|
|
case r4date:
|
|
length[numParms] = sizeof(double) ;
|
|
break ;
|
|
|
|
case r4log:
|
|
if ( info->functionI != E4FIELD_LOG )
|
|
{
|
|
if ( info->functionI == E4DELETED )
|
|
#ifndef S4CLIENT
|
|
if ( p4->expr.tagPtr ) /* data4 independent, so point to datafile */
|
|
info->p1 = (char *)&p4->expr.dataFile->record ;
|
|
else /* data4 dependent, so just point to record */
|
|
#endif
|
|
info->p1 = (char *)&p4->expr.data->record ;
|
|
else
|
|
{
|
|
info->i1 = (int)(length[numParms+1]) ;
|
|
lengthStatus = 1 ;
|
|
if ( length[numParms] < length[numParms+1] )
|
|
{
|
|
info->i1 = (int)(length[numParms]) ;
|
|
lengthStatus = -1 ;
|
|
}
|
|
if ( length[numParms] == length[numParms+1] )
|
|
lengthStatus = 0 ;
|
|
|
|
if ( info->functionI == E4GREATER )
|
|
{
|
|
if ( lengthStatus > 0 )
|
|
info->p1 = (char *)1L ;
|
|
else
|
|
info->p1 = (char *)0L ;
|
|
}
|
|
if ( info->functionI == E4LESS )
|
|
{
|
|
if ( lengthStatus < 0 )
|
|
info->p1 = (char *)1L ;
|
|
else
|
|
info->p1 = (char *)0L ;
|
|
}
|
|
}
|
|
}
|
|
length[numParms] = sizeof(int) ;
|
|
break ;
|
|
default:
|
|
return error4( codeBase, e4result, E90901 ) ;
|
|
}
|
|
|
|
/* make sure there is enough key space allocated for the type,
|
|
in case a partial evaluation occurs */
|
|
#ifdef S4CLIENT
|
|
storedKeyLen = (unsigned)(length[numParms]) ;
|
|
#else
|
|
switch( types[numParms] )
|
|
{
|
|
#ifdef S4FOX
|
|
case r4num:
|
|
case r4date:
|
|
case r4numDoub:
|
|
storedKeyLen = sizeof( double ) ;
|
|
break ;
|
|
#endif /* ifdef S4FOX */
|
|
#ifdef S4CLIPPER
|
|
case r4num: /* numeric field return, must fix length problem */
|
|
storedKeyLen = f4len( info->fieldPtr ) ;
|
|
break ;
|
|
case r4numDoub:
|
|
storedKeyLen = codeBase->numericStrLen ;
|
|
break ;
|
|
#endif /* ifdef S4CLIPPER */
|
|
#ifdef S4NDX
|
|
case r4num:
|
|
case r4date:
|
|
storedKeyLen = sizeof( double ) ;
|
|
break ;
|
|
#endif /* ifdef S4NDX */
|
|
#ifdef S4MDX
|
|
case r4num:
|
|
storedKeyLen = (int)sizeof( C4BCD ) ;
|
|
break ;
|
|
case r4numDoub:
|
|
storedKeyLen = (int)sizeof( C4BCD ) ;
|
|
break ;
|
|
case r4date:
|
|
case r4dateDoub:
|
|
storedKeyLen = sizeof( double ) ;
|
|
break ;
|
|
#endif /* S4MDX */
|
|
default:
|
|
storedKeyLen = (unsigned)(length[numParms]) ;
|
|
}
|
|
|
|
#ifdef S4FOX
|
|
storedKeyLen++ ; /* null entry will increase length by one */
|
|
#endif
|
|
#endif
|
|
|
|
u4allocAgain( codeBase, &codeBase->storedKey, &codeBase->storedKeyLen, (unsigned)storedKeyLen + 1 ) ;
|
|
|
|
if ( error4code( codeBase ) < 0 )
|
|
return -1 ;
|
|
#ifdef S4DATA_ALIGN
|
|
delta = 0 ;
|
|
switch(types[numParms])
|
|
{
|
|
case r4numDoub:
|
|
case r4dateDoub:
|
|
case r4num:
|
|
case r4date:
|
|
{
|
|
int rem ;
|
|
if ((rem=position[numParms]%sizeof(double)))
|
|
delta=sizeof(double)-rem;
|
|
}
|
|
}
|
|
info->resultPos=position[numParms]+delta;
|
|
#else
|
|
info->resultPos = position[numParms] ;
|
|
#endif
|
|
|
|
bufLenNeeded = length[numParms] ;
|
|
if ( info->functionI == E4CALC_FUNCTION )
|
|
bufLenNeeded = ((EXPR4CALC *)info->p1)->expr->lenEval ;
|
|
/* bufLenNeeded = ((EXPR4 *)info->p1)->lenEval ; */
|
|
if( bufLenNeeded > INT_MAX )
|
|
return error4( codeBase, e4overflow, E90901 ) ;
|
|
|
|
if( (types[numParms] == r4num || types[numParms] == r4date || types[numParms] == r4int) && length[numParms] < sizeof(double) )
|
|
position[numParms+1] = info->resultPos + sizeof(double) ;
|
|
else
|
|
position[numParms+1] = info->resultPos + (unsigned)length[numParms] ;
|
|
|
|
if ( info->resultPos + bufLenNeeded > (long)p4->expr.lenEval )
|
|
p4->expr.lenEval = info->resultPos + (unsigned)bufLenNeeded ;
|
|
|
|
info->len = (int)(length[numParms]) ;
|
|
info->numEntries = 1 ;
|
|
|
|
for( i = 0; i < info->numParms; i++ )
|
|
info->numEntries += numEntries[numParms+i] ;
|
|
|
|
numEntries[numParms] = info->numEntries ;
|
|
pointers[numParms] = info ;
|
|
|
|
numParms++ ;
|
|
if ( numParms >= E4MAX_STACK_ENTRIES )
|
|
if( codeBase->errExpr )
|
|
return error4( codeBase, e4overflow, E90901 ) ;
|
|
}
|
|
|
|
if ( numParms != 1 )
|
|
{
|
|
if( codeBase->errExpr )
|
|
error4( codeBase, e4result, E90901 ) ;
|
|
return -1 ;
|
|
}
|
|
|
|
for( i = 0; i < p4->expr.infoN; i++ )
|
|
{
|
|
info = p4->expr.info + i ;
|
|
info->function = (S4OPERATOR *)v4functions[info->functionI].functionPtr ;
|
|
}
|
|
|
|
p4->expr.lenEval += 1 ;
|
|
if ( codeBase->exprBufLen < (unsigned)p4->expr.lenEval )
|
|
if ( u4allocAgain( codeBase, &codeBase->exprWorkBuf, &codeBase->exprBufLen, p4->expr.lenEval ) == e4memory )
|
|
return error4stack( codeBase, e4memory, E90901 ) ;
|
|
|
|
p4->expr.len = (int)(length[0]) ;
|
|
p4->expr.type = types[0] ;
|
|
return 0 ;
|
|
}
|
|
|
|
int e4addConstant( E4PARSE *p4, const int iFunctions, const void *consPtr, const unsigned consLen )
|
|
{
|
|
E4INFO *info ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( p4 == 0 )
|
|
return error4( 0, e4parm_null, E90902 ) ;
|
|
#endif
|
|
|
|
info = e4functionAdd( &p4->expr, iFunctions ) ;
|
|
if ( info == 0 )
|
|
return -1 ;
|
|
info->i1 = p4->constants.pos ;
|
|
info->len = consLen ;
|
|
return s4stackPushStr( &p4->constants, consPtr, (int)consLen ) ;
|
|
}
|
|
|
|
E4INFO *e4functionAdd( EXPR4 *expr, const int iFunctions )
|
|
{
|
|
E4INFO *info ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( expr == 0 )
|
|
{
|
|
error4( 0, e4parm_null, E90903 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
if ( (unsigned)((expr->infoN+1)*sizeof(E4INFO)) > expr->codeBase->exprBufLen )
|
|
if ( u4allocAgain( expr->codeBase, &expr->codeBase->exprWorkBuf, &expr->codeBase->exprBufLen, sizeof(E4INFO) * (expr->infoN+10) ) == e4memory )
|
|
return 0 ;
|
|
|
|
info = (E4INFO *)expr->codeBase->exprWorkBuf + expr->infoN++ ;
|
|
|
|
info->functionI = iFunctions ;
|
|
info->numParms = v4functions[iFunctions].numParms ;
|
|
if ( info->numParms < 0 )
|
|
info->numParms = 2 ;
|
|
info->function = (S4OPERATOR *)v4functions[iFunctions].functionPtr ;
|
|
return info ;
|
|
}
|
|
|
|
static void e4functionPop( EXPR4 *expr )
|
|
{
|
|
expr->infoN-- ;
|
|
}
|
|
|
|
EXPR4 *S4FUNCTION expr4parseLow( DATA4 *d4, const char *exprPtr, TAG4FILE *tagPtr )
|
|
{
|
|
E4PARSE parse ;
|
|
char ops[128] ;
|
|
char constants[512] ;
|
|
char *src ;
|
|
int rc, infoLen, posConstants ;
|
|
EXPR4 *express4 ;
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( d4 == 0 || exprPtr == 0 )
|
|
{
|
|
error4( 0, e4parm_null, E90904 ) ;
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
if ( error4code( d4->codeBase ) < 0 )
|
|
return 0 ;
|
|
|
|
if ( d4->codeBase->exprBufLen > 0 )
|
|
memset( d4->codeBase->exprWorkBuf, 0, d4->codeBase->exprBufLen ) ;
|
|
|
|
memset( (void *)&parse, 0, sizeof(E4PARSE) ) ;
|
|
memset( ops, 0, sizeof(ops));
|
|
|
|
parse.expr.tagPtr = tagPtr ;
|
|
#ifdef S4FOX
|
|
parse.expr.vfpInfo = tagPtr ? &tagPtr->vfpInfo : 0 ;
|
|
#endif
|
|
parse.expr.data = d4 ;
|
|
parse.expr.source = (char *)exprPtr ;
|
|
parse.codeBase = d4->codeBase ;
|
|
parse.expr.codeBase = d4->codeBase ;
|
|
|
|
parse.op.ptr = ops ;
|
|
parse.op.len = sizeof(ops) ;
|
|
parse.op.codeBase = d4->codeBase ;
|
|
|
|
parse.constants.ptr = constants ;
|
|
parse.constants.len = sizeof(constants) ;
|
|
parse.constants.codeBase = d4->codeBase ;
|
|
|
|
s4scanInit( &parse.scan, (unsigned char *)exprPtr ) ;
|
|
|
|
rc = expr4parseExpr( &parse ) ;
|
|
if ( rc < 0 )
|
|
return 0 ;
|
|
|
|
if ( s4stackCur( &parse.op ) != E4NO_FUNCTION )
|
|
{
|
|
if( parse.codeBase->errExpr )
|
|
error4describe( parse.codeBase, e4complete, E90904, exprPtr, 0, 0 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
parse.expr.info = (E4INFO *)parse.codeBase->exprWorkBuf ;
|
|
parse.expr.dataFile = d4->dataFile ;
|
|
if ( e4massage( &parse ) < 0 )
|
|
return 0 ;
|
|
|
|
infoLen = parse.expr.infoN * sizeof(E4INFO) ;
|
|
posConstants = sizeof(EXPR4) + infoLen ;
|
|
|
|
express4 = (EXPR4 *)u4allocFree( d4->codeBase, (long)posConstants + parse.constants.len + parse.scan.len + 1L ) ;
|
|
if ( express4 == 0 )
|
|
return 0 ;
|
|
|
|
memcpy( (void *)express4, (void *)&parse.expr, sizeof(EXPR4) ) ;
|
|
|
|
express4->data = d4 ;
|
|
express4->dataFile = d4->dataFile ;
|
|
express4->info = (E4INFO *)( express4 + 1 ) ;
|
|
express4->constants = (char *) express4 + posConstants ;
|
|
src = express4->constants + parse.constants.len ;
|
|
express4->source = src ;
|
|
|
|
memcpy( (void *)express4->info, parse.codeBase->exprWorkBuf, (unsigned int)infoLen ) ;
|
|
memcpy( express4->constants, constants, parse.constants.len ) ;
|
|
strcpy( src, exprPtr ) ;
|
|
|
|
#ifdef S4CLIPPER
|
|
express4->keyLen = parse.expr.keyLen ;
|
|
express4->keyDec = parse.expr.keyDec ;
|
|
#endif
|
|
|
|
return express4 ;
|
|
}
|
|
|
|
/*EXPR4 *S4FUNCTION expr4parse( DATA4 *d4, char *exprPtr )*/
|
|
/*{*/
|
|
/* return expr4parseLow( d4, exprPtr, 0 ) ;*/
|
|
/*}*/
|
|
|
|
/* Looks at the input string and returns and puts a character code on the
|
|
result stack corresponding to the next operator. The operators all operate
|
|
on two operands. Ex. +,-,*,/, >=, <, .AND., ...
|
|
|
|
If the operator is ambiguous, return the arithmatic choice.
|
|
|
|
Returns -2 (Done), 0, -1 (Error)
|
|
*/
|
|
|
|
int e4getOperator( E4PARSE *p4, int *opReturn)
|
|
{
|
|
char ch ;
|
|
int op ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( p4 == 0 || opReturn == 0 )
|
|
return error4( 0, e4parm_null, E90505 ) ;
|
|
#endif
|
|
|
|
s4scanRange( &p4->scan, 1, ' ' ) ;
|
|
ch = s4scanChar(&p4->scan) ;
|
|
if ( ch==0 || ch==')' || ch==',' )
|
|
{
|
|
*opReturn = E4DONE ;
|
|
return 0 ;
|
|
}
|
|
|
|
op = e4lookup( p4->scan.ptr+p4->scan.pos, -1, E4FIRST_OPERATOR, E4LAST_OPERATOR ) ;
|
|
if ( op < 0 )
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4unrecOperator, E90905, (char *)p4->scan.ptr, 0, 0 ) ;
|
|
|
|
p4->scan.pos += v4functions[op].nameLen ;
|
|
*opReturn = op ;
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
/* e4lookup, searches 'v4functions' for an operator or function.
|
|
|
|
str - the function name
|
|
strLen - If 'strLen' is greater than or equal to zero it contains the
|
|
exact number of characters in 'str' to lookup. Otherwise,
|
|
as many as needed, provided an ending null is not reached,
|
|
are compared.
|
|
*/
|
|
|
|
int S4FUNCTION e4lookup( const unsigned char *str, const int strLen, const int startI, const int endI )
|
|
{
|
|
char uStr[9] ; /* Maximum # of function name characters plus one. */
|
|
int i ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( str == 0 || endI < startI )
|
|
return error4( 0, e4parm, E90906 ) ;
|
|
#endif
|
|
|
|
u4ncpy( uStr, (char *)str, sizeof( uStr ) ) ;
|
|
c4upper( uStr ) ;
|
|
|
|
for( i=startI; i<= endI; i++)
|
|
{
|
|
if ( v4functions[i].code < 0 )
|
|
break ;
|
|
if ( v4functions[i].name == 0 )
|
|
continue ;
|
|
#ifdef E4ANALYZE
|
|
if ( v4functions[i].nameLen >= (char)sizeof( uStr ) )
|
|
return error4( 0, e4result, E90906 ) ;
|
|
#endif
|
|
|
|
if ( v4functions[i].name[0] == uStr[0] )
|
|
if( strLen == v4functions[i].nameLen || strLen < 0 )
|
|
if ( strncmp( uStr, v4functions[i].name, (size_t)v4functions[i].nameLen ) == 0 )
|
|
return i ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
|
|
static int opToExpr( E4PARSE *p4 )
|
|
{
|
|
E4INFO *info ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( p4 == 0 )
|
|
return error4( 0, e4parm_null, E90907 ) ;
|
|
#endif
|
|
|
|
info = e4functionAdd( &p4->expr, s4stackPop(&p4->op) ) ;
|
|
if ( info == 0 )
|
|
return -1 ;
|
|
|
|
for( ; s4stackCur(&p4->op) == E4ANOTHER_PARM ; )
|
|
{
|
|
s4stackPop(&p4->op) ;
|
|
info->numParms++ ;
|
|
}
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
/*
|
|
Parses an expression consisting of value [[operator value] ...]
|
|
The expression is ended by a ')', a ',' or a '\0'.
|
|
Operators are only popped until a '(', a ',' or the start of the stack.
|
|
Left to right evaluation for operators of equal priority.
|
|
|
|
An ambiguous operator is one which can be interpreted differently
|
|
depending on its operands. However, its operands depend on the
|
|
priority of the operators and the evaluation order. Fortunately, the
|
|
priority of an ambigous operator is constant regardless of its
|
|
interpretation. Consequently, the evaluation order is determined first.
|
|
Then ambiguous operators can be exactly determined.
|
|
|
|
Ambigous operators:+, -, >, <, <=, >=, =, <>, #
|
|
|
|
Return
|
|
|
|
0 Normal
|
|
-1 Error
|
|
*/
|
|
|
|
int expr4parseExpr( E4PARSE *p4 )
|
|
{
|
|
int rc, opValue, opOnStack ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( p4 == 0 )
|
|
return error4( 0, e4parm_null, E90908 ) ;
|
|
#endif
|
|
|
|
rc = expr4parseValue( p4 ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90908 ) ;
|
|
|
|
for( ;; )
|
|
{
|
|
rc = e4getOperator( p4, &opValue ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90908 ) ;
|
|
if ( opValue == E4DONE ) /* Done */
|
|
{
|
|
while( s4stackCur(&p4->op) != E4L_BRACKET && s4stackCur(&p4->op) != E4COMMA
|
|
&& s4stackCur(&p4->op) != E4NO_FUNCTION )
|
|
{
|
|
rc = opToExpr( p4 ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90908 ) ;
|
|
}
|
|
return 0 ;
|
|
}
|
|
|
|
/* Everything with a higher or equal priority than 'opValue' must be
|
|
executed first. (equal because of left to right evaluation order)
|
|
Consequently, all high priority operators are sent to the result
|
|
stack.
|
|
*/
|
|
while ( s4stackCur( &p4->op ) >= 0 )
|
|
{
|
|
opOnStack = s4stackCur(&p4->op ) ;
|
|
if ( v4functions[opValue].priority <= v4functions[opOnStack].priority )
|
|
{
|
|
if ( opValue == opOnStack && (int)v4functions[opValue].numParms < 0 )
|
|
{
|
|
/* If repeated AND or OR operator, combine them into one with an
|
|
extra paramter. This makes the relate module optimization
|
|
algorithms easier. */
|
|
s4stackPop( &p4->op ) ;
|
|
s4stackPushInt( &p4->op, E4ANOTHER_PARM ) ;
|
|
break ;
|
|
}
|
|
else
|
|
{
|
|
rc = opToExpr( p4 ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90908 ) ;
|
|
}
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
|
|
s4stackPushInt( &p4->op, opValue ) ;
|
|
|
|
rc = expr4parseValue( p4 ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90908 ) ;
|
|
}
|
|
}
|
|
|
|
int expr4parseFunction( E4PARSE *p4, const char *startPtr, const int fLen )
|
|
{
|
|
int fNum, numParms, infoI1, infoLen, rc, rVal ;
|
|
char ch ;
|
|
#ifdef S4DATA_ALIGN
|
|
double doubVal ;
|
|
#endif
|
|
E4INFO *info, *rInfo ;
|
|
void *newOrTotalPtr = 0 ;
|
|
EXPR4CALC *calc ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( p4 == 0 || startPtr == 0 || fLen < 0 )
|
|
return error4( 0, e4parm, E90909 ) ;
|
|
#endif
|
|
|
|
infoI1 = infoLen = 0 ;
|
|
|
|
if ( error4code( p4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
fNum = e4lookup( (unsigned char *)startPtr, fLen, E4FIRST_FUNCTION, 0x7FFF) ;
|
|
if( fNum < 0 )
|
|
{
|
|
newOrTotalPtr = calc = expr4calcLookup( p4->codeBase, startPtr, fLen ) ;
|
|
if( calc == 0 )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4unrecFunction, E90909, (char *)p4->scan.ptr, 0, 0 ) ;
|
|
return e4unrecFunction ;
|
|
}
|
|
else
|
|
{
|
|
fNum = E4CALC_FUNCTION ;
|
|
#ifndef S4SERVER
|
|
if( calc->total != 0 )
|
|
{
|
|
fNum = E4TOTAL ;
|
|
newOrTotalPtr = calc->total ;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
s4stackPushInt( &p4->op, E4L_BRACKET ) ;
|
|
p4->scan.pos++ ;
|
|
|
|
numParms = 0 ;
|
|
for( ;; )
|
|
{
|
|
ch = s4scanChar( &p4->scan ) ;
|
|
if ( ch == 0 )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4rightMissing, E90909, (char *)p4->scan.ptr, 0, 0 ) ;
|
|
return e4rightMissing ;
|
|
}
|
|
if ( ch == ')')
|
|
{
|
|
p4->scan.pos++ ;
|
|
break ;
|
|
}
|
|
|
|
rc = expr4parseExpr( p4 ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90909 ) ;
|
|
numParms++ ;
|
|
|
|
while( s4scanChar( &p4->scan ) <= ' ' && s4scanChar( &p4->scan ) >='\1')
|
|
p4->scan.pos++ ;
|
|
|
|
if ( s4scanChar( &p4->scan ) == ')')
|
|
{
|
|
p4->scan.pos++ ;
|
|
break ;
|
|
}
|
|
if ( s4scanChar( &p4->scan ) != ',')
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4commaExpected, E90909, (char *)p4->scan.ptr, 0, 0 ) ;
|
|
return e4commaExpected ;
|
|
}
|
|
p4->scan.pos++ ;
|
|
}
|
|
|
|
s4stackPop( &p4->op ) ; /* pop the left bracket */
|
|
|
|
if ( fNum == E4STR )
|
|
{
|
|
infoLen= 10 ;
|
|
|
|
if ( numParms == 3 )
|
|
{
|
|
info = (E4INFO *) p4->codeBase->exprWorkBuf + p4->expr.infoN -1 ;
|
|
if ( info->functionI != E4DOUBLE )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4notConstant, E90909, p4->expr.source, 0, 0 ) ;
|
|
return e4notConstant ;
|
|
}
|
|
#ifdef S4DATA_ALIGN
|
|
memcpy( (void *)&doubVal, (p4->constants.ptr + info->i1), sizeof(double) ) ;
|
|
infoI1 = (int) doubVal ;
|
|
#else
|
|
infoI1 = (int) *(double *) (p4->constants.ptr + info->i1) ;
|
|
#endif
|
|
e4functionPop( &p4->expr ) ;
|
|
numParms-- ;
|
|
}
|
|
if ( numParms == 2 )
|
|
{
|
|
info = (E4INFO *)p4->codeBase->exprWorkBuf + p4->expr.infoN - 1 ;
|
|
if ( info->functionI != E4DOUBLE )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4notConstant, E90909, p4->expr.source, 0, 0 ) ;
|
|
return e4notConstant ;
|
|
}
|
|
#ifdef S4DATA_ALIGN
|
|
memcpy( (void *)&doubVal, (p4->constants.ptr + info->i1), sizeof(double) ) ;
|
|
infoLen = (int) doubVal ;
|
|
#else
|
|
infoLen = (int) *(double *) (p4->constants.ptr + info->i1) ;
|
|
#endif
|
|
|
|
e4functionPop( &p4->expr ) ;
|
|
numParms-- ;
|
|
}
|
|
if ( infoLen < 0 )
|
|
infoLen = 10 ;
|
|
if ( infoLen <= infoI1+1 )
|
|
infoI1 = infoLen - 2 ;
|
|
if ( infoI1 < 0 )
|
|
infoI1 = 0 ;
|
|
}
|
|
if ( numParms == 2 && fNum == E4RIGHT )
|
|
{
|
|
info = (E4INFO *)p4->codeBase->exprWorkBuf + p4->expr.infoN -1 ;
|
|
rInfo = info - 1 ; /* get the constant/field len */
|
|
if ( info->functionI != E4DOUBLE )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4notConstant, E90909, p4->expr.source, 0, 0 ) ;
|
|
return e4notConstant ;
|
|
}
|
|
#ifdef S4DATA_ALIGN
|
|
memcpy( (void *)&doubVal, (p4->constants.ptr + info->i1), sizeof(double) ) ;
|
|
infoI1 = (int) doubVal ;
|
|
#else
|
|
infoI1 = (int) *(double *) (p4->constants.ptr + info->i1) ;
|
|
#endif
|
|
if ( rInfo->fieldPtr != 0 ) /* is a field */
|
|
rVal = f4len( rInfo->fieldPtr ) - infoI1 ;
|
|
else /* assume constant */
|
|
rVal = rInfo->len - infoI1 ;
|
|
infoLen = infoI1 ;
|
|
infoI1 = rVal ;
|
|
if ( infoLen < 0 )
|
|
infoLen = 0 ;
|
|
e4functionPop( &p4->expr ) ;
|
|
numParms-- ;
|
|
}
|
|
if ((numParms == 3 && fNum == E4SUBSTR) || (numParms == 2 && fNum == E4LEFT))
|
|
{
|
|
info = (E4INFO *)p4->codeBase->exprWorkBuf + p4->expr.infoN -1 ;
|
|
if ( info->functionI != E4DOUBLE )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4notConstant, E90909, p4->expr.source, 0, 0 ) ;
|
|
return e4notConstant ;
|
|
}
|
|
#ifdef S4DATA_ALIGN
|
|
memcpy( (void *)&doubVal, (p4->constants.ptr + info->i1), sizeof(double) ) ;
|
|
infoLen = (int) doubVal ;
|
|
#else
|
|
infoLen = (int) *(double *) (p4->constants.ptr + info->i1) ;
|
|
#endif
|
|
e4functionPop( &p4->expr ) ;
|
|
numParms-- ;
|
|
}
|
|
if ( numParms == 2 && fNum == E4SUBSTR )
|
|
{
|
|
info = (E4INFO *) p4->codeBase->exprWorkBuf + p4->expr.infoN -1 ;
|
|
if ( info->functionI != E4DOUBLE )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
error4describe( p4->codeBase, e4notConstant, E90909, p4->expr.source, 0, 0 ) ;
|
|
return e4notConstant ;
|
|
}
|
|
#ifdef S4DATA_ALIGN
|
|
memcpy( (void *)&doubVal, (p4->constants.ptr + info->i1), sizeof(double) ) ;
|
|
infoI1 = (int) doubVal ;
|
|
#else
|
|
infoI1 = (int) *(double *) (p4->constants.ptr + info->i1) ;
|
|
#endif
|
|
infoI1-- ;
|
|
e4functionPop( &p4->expr ) ;
|
|
numParms-- ;
|
|
}
|
|
|
|
if ( error4code( p4->codeBase ) < 0 )
|
|
return -1 ;
|
|
|
|
if ( numParms != v4functions[fNum].numParms && (int)v4functions[fNum].numParms >= 0 )
|
|
{
|
|
if( fNum == E4DTOC && numParms == 2 )
|
|
{
|
|
e4functionPop( &p4->expr ) ;
|
|
numParms-- ;
|
|
fNum = E4DTOS ;
|
|
}
|
|
else
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4numParms, E80906, v4functions[fNum].name, (char *)p4->scan.ptr, 0 ) ;
|
|
return e4numParms ;
|
|
}
|
|
}
|
|
|
|
info = e4functionAdd( &p4->expr, fNum ) ;
|
|
if ( info == 0 )
|
|
return -1 ;
|
|
|
|
info->i1 = infoI1 ;
|
|
info->len = infoLen ;
|
|
|
|
info->numParms = numParms ;
|
|
if ( fNum == E4CALC_FUNCTION || fNum == E4TOTAL )
|
|
info->p1 = (char *)newOrTotalPtr ;
|
|
return 0 ;
|
|
}
|
|
|
|
int expr4parseValue( E4PARSE *p4 )
|
|
{
|
|
FIELD4 *fieldPtr ;
|
|
char ch, searchChar ;
|
|
const unsigned char *startPtr ;
|
|
int rc, iFunctions, len, iFunction, savePos ;
|
|
double d ;
|
|
E4INFO *expr, *info ;
|
|
DATA4 *basePtr ;
|
|
char bName[11], fName[11] ;
|
|
|
|
#ifdef E4PARM_LOW
|
|
if ( p4 == 0 )
|
|
return error4( 0, e4parm_null, E90910 ) ;
|
|
#endif
|
|
|
|
if ( error4code( p4->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
s4scanRange( &p4->scan, ' ', ' ' ) ;
|
|
|
|
/* expression */
|
|
|
|
if ( s4scanChar( &p4->scan ) == '(')
|
|
{
|
|
p4->scan.pos++ ;
|
|
|
|
s4stackPushInt( &p4->op, E4L_BRACKET) ;
|
|
rc = expr4parseExpr( p4 ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90910 ) ;
|
|
|
|
while ( s4scanChar( &p4->scan ) <= ' ' &&
|
|
s4scanChar( &p4->scan ) != 0) p4->scan.pos++ ;
|
|
|
|
if ( s4scanChar( &p4->scan ) != ')' )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4rightMissing, E90910, (char *)p4->scan.ptr, 0, 0 ) ;
|
|
return e4rightMissing ;
|
|
}
|
|
p4->scan.pos++ ;
|
|
s4stackPop( &p4->op ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
/* logical */
|
|
if ( s4scanChar( &p4->scan ) == '.' )
|
|
{
|
|
iFunctions = e4lookup( p4->scan.ptr+p4->scan.pos, -1, E4FIRST_LOG, E4LAST_LOG ) ;
|
|
if ( iFunctions >= 0 )
|
|
{
|
|
p4->scan.pos += v4functions[iFunctions].nameLen ;
|
|
|
|
if ( strcmp( v4functions[iFunctions].name, ".NOT." ) == 0 )
|
|
{
|
|
rc = expr4parseValue( p4 ) ; /* One operand operation */
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90910 ) ;
|
|
s4stackPushInt( &p4->op, iFunctions ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
expr = e4functionAdd( &p4->expr, iFunctions ) ;
|
|
if ( expr == 0 )
|
|
return -1 ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
/* string */
|
|
ch = s4scanChar( &p4->scan ) ;
|
|
if ( ch == '\'' || ch == '\"' || ch == '[' )
|
|
{
|
|
if ( ch == '[' )
|
|
searchChar = ']' ;
|
|
else
|
|
searchChar = ch ;
|
|
|
|
p4->scan.pos++ ;
|
|
startPtr = p4->scan.ptr + p4->scan.pos ;
|
|
|
|
len = s4scanSearch( &p4->scan, searchChar ) ;
|
|
if ( s4scanChar( &p4->scan ) != searchChar )
|
|
if ( len < 0 )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4unterminated, E90910, (char *)p4->scan.ptr, 0, 0 ) ;
|
|
return e4unterminated ;
|
|
}
|
|
p4->scan.pos++ ;
|
|
|
|
rc = e4addConstant( p4, E4STRING, startPtr, (unsigned int)len ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90910 ) ;
|
|
return 0 ;
|
|
}
|
|
|
|
/* real */
|
|
ch = s4scanChar( &p4->scan ) ;
|
|
if ( ((ch >='0') && (ch <='9')) || (ch == '-') || (ch == '+') || (ch == '.') )
|
|
{
|
|
startPtr = p4->scan.ptr + p4->scan.pos ;
|
|
savePos = p4->scan.pos ;
|
|
p4->scan.pos++ ;
|
|
len = 1 ;
|
|
|
|
while( ((s4scanChar( &p4->scan ) >= '0') && (s4scanChar( &p4->scan ) <= '9')) || (s4scanChar( &p4->scan ) == '.') )
|
|
{
|
|
if ( s4scanChar( &p4->scan ) == '.' )
|
|
{
|
|
if ( strnicmp( (char *)p4->scan.ptr + p4->scan.pos, ".AND.", 5) == 0 ||
|
|
strnicmp( (char *)p4->scan.ptr + p4->scan.pos, ".OR.", 4) == 0 ||
|
|
strnicmp( (char *)p4->scan.ptr + p4->scan.pos, ".NOT.", 5) == 0 )
|
|
break ;
|
|
/* if the next value is a character, then we have a database
|
|
with a number as its name/alias. (i.e. 111.afld), since
|
|
numerics are invalid to being a field name, MUST be a
|
|
number if a numeric after the decimal point... */
|
|
if ( toupper( s4scanChar( &p4->scan + 1 ) ) >= 'A' && toupper( s4scanChar( &p4->scan + 1 ) ) <= 'Z' )
|
|
{
|
|
p4->scan.pos++ ; /* make sure a letter is identified below... */
|
|
break ;
|
|
}
|
|
}
|
|
len++ ;
|
|
p4->scan.pos++ ;
|
|
}
|
|
|
|
/* check to see if maybe actually a database name starting with a numeric... */
|
|
if ( toupper( s4scanChar( &p4->scan ) ) >= 'A' && toupper( s4scanChar( &p4->scan ) ) <= 'Z' )
|
|
p4->scan.pos = savePos ;
|
|
else
|
|
{
|
|
d = c4atod( (char *)startPtr, len ) ;
|
|
rc = e4addConstant( p4, E4DOUBLE, &d, sizeof(d) ) ;
|
|
if ( rc < 0 )
|
|
return error4stack( p4->codeBase, (short)rc, E90910 ) ;
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
/* function or field */
|
|
if ( u4nameChar( s4scanChar( &p4->scan ) ) )
|
|
{
|
|
startPtr = p4->scan.ptr + p4->scan.pos ;
|
|
|
|
for( len = 0 ; u4nameChar( s4scanChar( &p4->scan ) ) ; len++ )
|
|
p4->scan.pos++ ;
|
|
|
|
s4scanRange( &p4->scan, (char)0, ' ' ) ;
|
|
|
|
if ( s4scanChar( &p4->scan ) == '(' )
|
|
return expr4parseFunction( p4, (char *)startPtr, len ) ;
|
|
|
|
basePtr = 0 ;
|
|
|
|
#ifdef S4FOX
|
|
if ( s4scanChar( &p4->scan ) == '.' )
|
|
{ /* for fox, same as -> */
|
|
if ( len > 10 )
|
|
len = 10 ;
|
|
c4memmove( bName, startPtr, (size_t)len ) ;
|
|
bName[len] = '\0' ;
|
|
|
|
basePtr = tran4dataName( code4trans( p4->codeBase ), bName, 0L, 1 ) ;
|
|
}
|
|
#endif
|
|
|
|
if ( s4scanChar( &p4->scan ) == '-' )
|
|
if ( p4->scan.ptr[p4->scan.pos+1] == '>')
|
|
{
|
|
if ( len > 10 )
|
|
len = 10 ;
|
|
c4memmove( bName, startPtr, (size_t)len ) ;
|
|
bName[len] = '\0' ;
|
|
|
|
basePtr = tran4dataName( code4trans( p4->codeBase ), bName, 0L, 1 ) ;
|
|
|
|
if ( basePtr == 0 )
|
|
{
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4dataName, E90910, bName, (char *)p4->scan.ptr, (char *) 0 ) ;
|
|
return e4dataName ;
|
|
}
|
|
p4->scan.pos++ ;
|
|
}
|
|
|
|
|
|
if ( basePtr != 0 )
|
|
{
|
|
if ( p4->expr.tagPtr ) /* data4 independent, so point to datafile */
|
|
return error4( p4->codeBase, e4tagExpr, E80909 ) ;
|
|
|
|
p4->scan.pos++ ;
|
|
|
|
startPtr = p4->scan.ptr + p4->scan.pos ;
|
|
for( len = 0 ; u4nameChar( s4scanChar( &p4->scan ) ) ; len++ )
|
|
p4->scan.pos++ ;
|
|
}
|
|
else
|
|
basePtr = (DATA4 *)p4->expr.data ;
|
|
|
|
if ( len <= 10)
|
|
{
|
|
c4memmove( fName, startPtr, (size_t)len ) ;
|
|
fName[len] = 0 ;
|
|
fieldPtr = d4field( basePtr, fName ) ;
|
|
if ( fieldPtr == 0 )
|
|
return -1 ;
|
|
|
|
#ifdef S4CLIPPER
|
|
p4->expr.keyLen = fieldPtr->len ;
|
|
p4->expr.keyDec = fieldPtr->dec ;
|
|
#endif
|
|
|
|
iFunction = 0 ;
|
|
switch( fieldPtr->type )
|
|
{
|
|
case r4num:
|
|
case r4float:
|
|
iFunction = E4FIELD_NUM_S ;
|
|
break ;
|
|
case r4str:
|
|
iFunction = E4FIELD_STR ;
|
|
break ;
|
|
case r4date:
|
|
iFunction = E4FIELD_DATE_S ;
|
|
break ;
|
|
case r4log:
|
|
iFunction = E4FIELD_LOG ;
|
|
break ;
|
|
case r4memo:
|
|
#ifdef S4MEMO_OFF
|
|
return error4( p4->codeBase, e4notMemo, E90910 ) ;
|
|
#else
|
|
iFunction = E4FIELD_MEMO ;
|
|
break ;
|
|
#endif
|
|
#ifdef S4CLIENT_OR_FOX
|
|
/* visual Fox 3.0 new field types */
|
|
case r4currency:
|
|
iFunction = E4FIELD_CUR ;
|
|
break ;
|
|
case r4dateTime:
|
|
iFunction = E4FIELD_DTTIME ;
|
|
break ;
|
|
case r4double:
|
|
iFunction = E4FIELD_DOUB ;
|
|
break ;
|
|
case r4int:
|
|
iFunction = E4FIELD_INT ;
|
|
break ;
|
|
#endif
|
|
default:
|
|
if( p4->codeBase->errExpr )
|
|
return error4( p4->codeBase, e4typeSub, E80901 ) ;
|
|
return -1 ;
|
|
}
|
|
|
|
info = e4functionAdd( &p4->expr, iFunction ) ;
|
|
if ( info == 0 )
|
|
return -1 ;
|
|
info->fieldNo = f4number( fieldPtr ) ;
|
|
info->fieldPtr = fieldPtr ;
|
|
#ifndef S4CLIENT
|
|
if ( p4->expr.tagPtr )
|
|
info->p1 = (char *)&basePtr->dataFile->record ;
|
|
else
|
|
#endif
|
|
info->p1 = (char *)&basePtr->record ;
|
|
info->i1 = fieldPtr->offset ;
|
|
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
if( p4->codeBase->errExpr )
|
|
return error4describe( p4->codeBase, e4unrecValue, E90910, (char *)p4->scan.ptr, 0, 0 ) ;
|
|
return e4unrecValue ;
|
|
}
|
|
|
|
int s4stackPop( S4STACK *s4 )
|
|
{
|
|
int retValue ;
|
|
|
|
retValue = s4stackCur(s4) ;
|
|
|
|
if ( s4->pos >= sizeof(int) )
|
|
s4->pos -= sizeof(int) ;
|
|
return retValue ;
|
|
}
|
|
|
|
int s4stackCur( S4STACK *s4 )
|
|
{
|
|
int pos, curData ;
|
|
|
|
if ( s4->pos < sizeof(int) )
|
|
return E4NO_FUNCTION ;
|
|
pos = s4->pos - sizeof(int) ;
|
|
memcpy( (void *)&curData, s4->ptr+pos, sizeof(int) ) ;
|
|
return curData ;
|
|
}
|
|
|
|
int s4stackPushInt( S4STACK *s4, const int i )
|
|
{
|
|
return s4stackPushStr( s4, &i, sizeof(i)) ;
|
|
}
|
|
|
|
int s4stackPushStr( S4STACK *s4, const void *p, const int len )
|
|
{
|
|
char *oldPtr ;
|
|
|
|
if ( error4code( s4->codeBase ) < 0 )
|
|
return -1 ;
|
|
|
|
if ( s4->pos+len > s4->len )
|
|
{
|
|
oldPtr = s4->ptr ;
|
|
if ( ! s4->doExtend )
|
|
s4->ptr = 0 ;
|
|
else
|
|
s4->ptr = (char *)u4allocFree( s4->codeBase, (long)s4->len + 256L ) ;
|
|
if ( s4->ptr == 0 )
|
|
{
|
|
s4->ptr = oldPtr ;
|
|
if ( s4->codeBase->errExpr )
|
|
return error4( s4->codeBase, e4memory, E90911 ) ;
|
|
return e4memory ;
|
|
}
|
|
memcpy( s4->ptr, oldPtr, s4->len ) ;
|
|
u4free( oldPtr ) ;
|
|
s4->len += 256 ;
|
|
|
|
return s4stackPushStr( s4, p, len ) ;
|
|
}
|
|
else
|
|
{
|
|
memcpy( s4->ptr+s4->pos, p, (unsigned int)len ) ;
|
|
s4->pos += len ;
|
|
}
|
|
return 0 ;
|
|
}
|
|
|
|
unsigned char s4scanChar( S4SCAN *s4 )
|
|
{
|
|
if ( s4->pos >= s4->len )
|
|
return 0 ;
|
|
return s4->ptr[s4->pos] ;
|
|
}
|
|
|
|
void s4scanInit( S4SCAN *s4, const unsigned char *p )
|
|
{
|
|
s4->ptr = p ;
|
|
s4->pos = 0 ;
|
|
s4->len = strlen( (char *)p ) ;
|
|
}
|
|
|
|
int s4scanRange( S4SCAN *s4, const int startChar, const int endChar )
|
|
{
|
|
int count ;
|
|
|
|
for ( count = 0; s4->pos < s4->len; s4->pos++, count++ )
|
|
if ( s4->ptr[s4->pos] < startChar || s4->ptr[s4->pos] > endChar )
|
|
return count ;
|
|
return count ;
|
|
}
|
|
|
|
int s4scanSearch( S4SCAN *s4, const char searchChar )
|
|
{
|
|
int count ;
|
|
|
|
for ( count = 0; s4->pos < s4->len; s4->pos++, count++ )
|
|
if ( s4->ptr[s4->pos] == searchChar )
|
|
return count ;
|
|
return count ;
|
|
}
|
|
|
|
#ifdef S4VB_DOS
|
|
|
|
EXPR4 *expr4parse_v( DATA4 *d4, char *expr )
|
|
{
|
|
return expr4parseLow( d4, c4str(expr), 0 ) ;
|
|
}
|
|
|
|
#endif
|