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
 |