which included commits to RCS files with non-trunk default branches. git-svn-id: svn://10.65.10.50/trunk@976 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1244 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1244 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* e4parse.c   (c)Copyright Sequiter Software Inc., 1990-1994.  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 3rd parameter
 | |
|    IIF must return a predictable length and type
 | |
|    TRIM and LTRIM returns an unpredictable length.  Its result
 | |
|    can be operated on by the concatenate operator only.
 | |
|    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>
 | |
| 
 | |
| void e4function_pop( 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 'code_base->expr_buf_len' 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 parm_pos, i_parm, is_ok, code_on, i_info, num_parms ;
 | |
|   int type_should_be, len, length_status, i, done_trim_memo_or_calc ;
 | |
|   int position[E4MAX_STACK_ENTRIES+1] ;
 | |
|   long length[E4MAX_STACK_ENTRIES] ;
 | |
|   long buf_len_needed ;
 | |
|   int types[E4MAX_STACK_ENTRIES] ;
 | |
|   int num_entries[E4MAX_STACK_ENTRIES] ;
 | |
|   E4INFO *pointers[E4MAX_STACK_ENTRIES] ;
 | |
|   CODE4 *code_base ;
 | |
|   unsigned stored_key_len ;
 | |
| 
 | |
|   code_base = p4->code_base ;
 | |
|   num_parms = done_trim_memo_or_calc = 0 ;
 | |
|   buf_len_needed = 0 ;
 | |
| 
 | |
|   position[0] = 0 ; /* The first parameter can be placed at position 0 */
 | |
| 
 | |
|   for( i_info = 0; i_info < p4->expr.info_n; i_info++ )
 | |
|   {
 | |
|     info = p4->expr.info + i_info ;
 | |
| 
 | |
|     /* Check the parameters types */
 | |
|     code_on = v4functions[info->function_i].code ;
 | |
|     if ( v4functions[info->function_i].num_parms != (char)info->num_parms )
 | |
|       if ( v4functions[info->function_i].num_parms > 0 )
 | |
|       {
 | |
|         if( code_base->expr_error )
 | |
|           e4( code_base, e4num_parms, p4->expr.source ) ;
 | |
|         return -1 ;
 | |
|       }
 | |
| 
 | |
|     for(;;)
 | |
|     {
 | |
|       if ( code_on != v4functions[info->function_i].code )
 | |
|       {
 | |
|         if( code_base->expr_error )
 | |
|           e4( code_base, e4type_sub, p4->expr.source ) ;
 | |
|         return -1 ;
 | |
|       }
 | |
| 
 | |
|       is_ok = 1 ;
 | |
| 
 | |
|       for( i_parm = 0; i_parm < info->num_parms; i_parm++ )
 | |
|       {
 | |
|         if ( (int)v4functions[info->function_i].num_parms < 0 )
 | |
|           type_should_be = v4functions[info->function_i].type[0] ;
 | |
|         else
 | |
|           type_should_be = v4functions[info->function_i].type[i_parm] ;
 | |
| 
 | |
|         parm_pos = num_parms - info->num_parms + i_parm ;
 | |
| 
 | |
|         if ( types[parm_pos] != type_should_be )
 | |
|         {
 | |
|           if ( types[parm_pos] == r4date && type_should_be == r4date_doub )
 | |
|           {
 | |
|             pointers[parm_pos]->function_i = E4FIELD_DATE_D ;
 | |
|             length[parm_pos] = sizeof(double) ;
 | |
|             continue ;
 | |
|           }
 | |
|           if ( types[parm_pos] == r4num && type_should_be == r4num_doub )
 | |
|           {
 | |
|             pointers[parm_pos]->function_i = E4FIELD_NUM_D ;
 | |
|             length[parm_pos] = sizeof(double) ;
 | |
|             continue ;
 | |
|           }
 | |
| 
 | |
|           info->function_i++ ;
 | |
|           is_ok = 0 ;
 | |
|           break ;
 | |
|         }
 | |
|       }
 | |
|       if ( is_ok )
 | |
|         break ;
 | |
|     }
 | |
| 
 | |
|     switch( info->function_i )
 | |
|     {
 | |
|     case E4CONCATENATE:
 | |
|     case E4CONCAT_TWO:
 | |
|     case E4TRIM:
 | |
|     case E4LTRIM:
 | |
|     case E4UPPER:
 | |
|     case E4SUBSTR:
 | |
|     case E4LEFT:
 | |
| #ifdef S4CLIPPER
 | |
|     case E4DESCEND_STR:
 | |
|       /*          case E4DESCEND_STR+1: */
 | |
| #endif
 | |
| #ifndef S4MEMO_OFF
 | |
|     case E4FIELD_MEMO:
 | |
| #endif
 | |
|       for( i_parm = 1; i_parm <= info->num_parms; i_parm++ )
 | |
|       {
 | |
|         E4INFO *info_parm = pointers[num_parms-i_parm] ;
 | |
|         if ( info_parm->function_i == E4FIELD_STR )
 | |
|           /* Make sure the parameter is put on the stack. */
 | |
|           info_parm->function_i = E4FIELD_STR_CAT ;
 | |
|         if ( info->function_i == E4CONCATENATE  &&  done_trim_memo_or_calc )
 | |
|           info->function_i = E4CONCAT_TRIM ;
 | |
|       }
 | |
|       break ;
 | |
|     default:
 | |
|       break ;
 | |
|     }
 | |
| 
 | |
|     num_parms -= info->num_parms ;
 | |
|     if ( num_parms < 0 )
 | |
|     {
 | |
|       if( code_base->expr_error )
 | |
|         e4( code_base, e4result, 0 ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
| 
 | |
|     types[num_parms] = v4functions[info->function_i].return_type ;
 | |
| 
 | |
|     if ( info->function_i == E4CALC_FUNCTION )
 | |
|       types[num_parms] = expr4type( ((EXPR4CALC *) info->p1)->expr ) ;
 | |
|     switch( types[num_parms] )
 | |
|     {
 | |
|     case r4str:
 | |
|       switch( info->function_i )
 | |
|       {
 | |
|       case E4FIELD_STR:
 | |
|       case E4FIELD_STR_CAT:
 | |
|         length[num_parms] = f4len( info->field_ptr ) ;
 | |
|         break ;
 | |
| 
 | |
| #ifndef S4MEMO_OFF
 | |
|       case E4FIELD_MEMO:
 | |
|         length[num_parms] = code_base->mem_size_memo_expr ;
 | |
|         done_trim_memo_or_calc = 1 ;
 | |
|         break ;
 | |
| #endif  /* S4MEMO_OFF */
 | |
| 
 | |
|       case E4CONCATENATE:
 | |
|       case E4CONCAT_TWO:
 | |
|       case E4CONCAT_TRIM:
 | |
|         info->i1 = (int) (length[num_parms]) ;
 | |
|         length[num_parms] += length[num_parms+1] ;
 | |
|         break ;
 | |
| 
 | |
|       case E4IIF:
 | |
|         if ( length[num_parms+1] != length[num_parms+2] )
 | |
|         {
 | |
|           if( code_base->expr_error )
 | |
|             e4describe( code_base, e4length_err, p4->expr.source, 0, 0 ) ;
 | |
|           return -1 ;
 | |
|         }
 | |
|         length[num_parms] = length[num_parms+1] ;
 | |
|         break ;
 | |
| 
 | |
|       case E4DTOS:
 | |
|       case E4DTOS+1:
 | |
|         length[num_parms] = 8 ;
 | |
|         break ;
 | |
| 
 | |
|       case E4DTOC:
 | |
|       case E4DTOC+1:
 | |
|       case E4CTOD:
 | |
|         length[num_parms] = 8 ;
 | |
|         info->i1 = p4->constants.pos ;
 | |
|         len = strlen( code_base->date_format) ;
 | |
|         s4stack_push_str( &p4->constants, code_base->date_format,
 | |
|                          len + 1 ) ;
 | |
|         if ( info->function_i == E4DTOC || info->function_i == E4DTOC+1 )
 | |
|           length[num_parms] = len ;
 | |
|         break ;
 | |
| 
 | |
|       case E4DEL:
 | |
|         length[num_parms] = 1 ;
 | |
|         info->p1 = (char *)&p4->expr.data->record ;
 | |
|         break ;
 | |
| 
 | |
|       case E4CALC_FUNCTION:
 | |
|         done_trim_memo_or_calc = 1 ;
 | |
|         length[num_parms] = expr4len( ((EXPR4CALC *) info->p1)->expr ) ;
 | |
|         break ;
 | |
| 
 | |
|       case E4SUBSTR:
 | |
|       case E4LEFT:
 | |
|         if ( info->i1 > (int)(length[num_parms]) )
 | |
|           info->i1 = (int)(length[num_parms]) ;
 | |
|         if ( info->i1 < 0 )
 | |
|           info->i1 = 0 ;
 | |
|         length[num_parms]  -= info->i1 ;
 | |
|         if ( info->len > (int)(length[num_parms]) )
 | |
|           info->len = (int)(length[num_parms]) ;
 | |
|         length[num_parms] = info->len ;
 | |
|         break ;
 | |
| 
 | |
|       case E4TIME:
 | |
|         length[num_parms] = 8 ;
 | |
|         break ;
 | |
| 
 | |
|       case E4TRIM:
 | |
|       case E4LTRIM:
 | |
|         done_trim_memo_or_calc = 1 ;
 | |
|         p4->expr.has_trim = 1 ;
 | |
|         break ;
 | |
| 
 | |
|       case E4UPPER:
 | |
|       case E4DESCEND_STR:
 | |
|         /*             case E4DESCEND_STR+1: */
 | |
|         break ;
 | |
| 
 | |
|       default:
 | |
|         length[num_parms] = info->len ;
 | |
|       }
 | |
|       break ;
 | |
| 
 | |
|     case r4num:
 | |
|       length[num_parms] = f4len( info->field_ptr ) ;
 | |
|       break ;
 | |
| 
 | |
|     case r4num_doub:
 | |
|     case r4date_doub:
 | |
|       length[num_parms] = sizeof(double) ;
 | |
|       if ( info->function_i == E4CTOD )
 | |
|       {
 | |
|         info->i1 = p4->constants.pos ;
 | |
|         s4stack_push_str( &p4->constants, code_base->date_format,
 | |
|                          strlen( code_base->date_format) + 1 ) ;
 | |
|       }
 | |
|       if ( info->function_i == E4RECCOUNT || info->function_i == E4RECNO )
 | |
|         info->p1 = (char *) p4->expr.data ;
 | |
|       break ;
 | |
| 
 | |
|     case r4date:
 | |
|       length[num_parms] = 8 ;
 | |
|       break ;
 | |
| 
 | |
|     case r4log:
 | |
|       if ( info->function_i != E4FIELD_LOG )
 | |
|       {
 | |
|         if ( info->function_i == E4DELETED )
 | |
|           info->p1 = (char *) &p4->expr.data->record ;
 | |
|         else
 | |
|         {
 | |
|           info->i1 = (int)(length[num_parms+1]) ;
 | |
|           length_status = 1 ;
 | |
|           if ( length[num_parms] < length[num_parms+1] )
 | |
|           {
 | |
|             info->i1 = (int)(length[num_parms]) ;
 | |
|             length_status = -1 ;
 | |
|           }
 | |
|           if ( length[num_parms] == length[num_parms+1] )
 | |
|             length_status = 0 ;
 | |
| 
 | |
|           if ( info->function_i == E4GREATER )
 | |
|           {
 | |
|             if ( length_status > 0 )
 | |
|               info->p1 = (char *)1L ;
 | |
|             else
 | |
|               info->p1 = (char *)0 ;
 | |
|           }
 | |
|           if ( info->function_i == E4LESS )
 | |
|           {
 | |
|             if ( length_status < 0 )
 | |
|               info->p1 = (char *)1L ;
 | |
|             else
 | |
|               info->p1 = (char *)0 ;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       length[num_parms] = sizeof(int) ;
 | |
|       break ;
 | |
| 
 | |
|     default:
 | |
| #ifdef S4DEBUG
 | |
|       return e4( code_base, e4result, 0 ) ;
 | |
| #else
 | |
|       return -1 ;
 | |
| #endif
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /* make sure there is enough key space allocated for the type,
 | |
|        in case a partial evaluation occurs */
 | |
|     switch( types[num_parms] )
 | |
|     {
 | |
| #ifdef S4FOX
 | |
|     case r4num:
 | |
|     case r4date:
 | |
|     case r4num_doub:
 | |
|       stored_key_len = sizeof( double ) ;
 | |
|       break ;
 | |
| #endif  /*  ifdef S4FOX      */
 | |
| #ifdef S4CLIPPER
 | |
|     case r4num:  /* numeric field return, must fix length problem */
 | |
|       stored_key_len = f4len( info->field_ptr ) ;
 | |
|       break ;
 | |
|     case r4num_doub:
 | |
|       stored_key_len = code_base->numeric_str_len ;
 | |
|       break ;
 | |
| #endif  /*  ifdef S4CLIPPER  */
 | |
| #ifdef S4NDX
 | |
|     case r4num:
 | |
|     case r4date:
 | |
|       stored_key_len = sizeof( double ) ;
 | |
|       break ;
 | |
| #endif  /*  ifdef S4NDX  */
 | |
| #ifdef S4MDX
 | |
|     case r4num:
 | |
|       stored_key_len = (int)sizeof( C4BCD ) ;
 | |
|       break ;
 | |
|     case r4num_doub:
 | |
|       stored_key_len = (int)sizeof( C4BCD ) ;
 | |
|       break ;
 | |
|     case r4date:
 | |
|     case r4date_doub:
 | |
|       stored_key_len = sizeof( double ) ;
 | |
|       break ;
 | |
| #endif  /* S4MDX */
 | |
|     default:
 | |
|       stored_key_len = (unsigned)(length[num_parms]) ;
 | |
|     }
 | |
| 
 | |
|     u4alloc_again( code_base, &code_base->stored_key, &code_base->stored_key_len, stored_key_len + 1 ) ;
 | |
| 
 | |
|     if ( code_base->error_code < 0 )
 | |
|       return -1 ;
 | |
| 
 | |
|     info->result_pos = position[num_parms] ;
 | |
|     buf_len_needed = length[num_parms] ;
 | |
|     if ( info->function_i == E4CALC_FUNCTION )
 | |
|       buf_len_needed = ((EXPR4 *)info->p1)->len_eval ;
 | |
|     if( buf_len_needed > INT_MAX )
 | |
|     {
 | |
|       e4( code_base, e4overflow, 0 ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
| 
 | |
|     if( (types[num_parms] == r4num || types[num_parms] == r4date)  &&
 | |
|        length[num_parms] < sizeof(double) )
 | |
|       position[num_parms+1] = position[num_parms] + sizeof(double) ;
 | |
|     else
 | |
|       position[num_parms+1] = position[num_parms] + (unsigned)length[num_parms] ;
 | |
|     if ( position[num_parms] + buf_len_needed > p4->expr.len_eval )
 | |
|       p4->expr.len_eval = position[num_parms] + (unsigned)buf_len_needed ;
 | |
|     info->len = (int)(length[num_parms]) ;
 | |
| 
 | |
|     info->num_entries = 1 ;
 | |
|     for( i = 0; i < info->num_parms; i++ )
 | |
|       info->num_entries += num_entries[num_parms+i] ;
 | |
| 
 | |
|     num_entries[num_parms] = info->num_entries ;
 | |
|     pointers[num_parms] = info ;
 | |
| 
 | |
|     num_parms++ ;
 | |
|     if ( num_parms >= E4MAX_STACK_ENTRIES )
 | |
|     {
 | |
|       if( code_base->expr_error )
 | |
|         e4( code_base, e4overflow, 0 ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ( num_parms != 1 )
 | |
|   {
 | |
|     if( code_base->expr_error )
 | |
|       e4( code_base, e4result, 0 ) ;
 | |
|     return -1 ;
 | |
|   }
 | |
| 
 | |
|   for( i = 0; i < p4->expr.info_n; i++ )
 | |
|   {
 | |
|     info = p4->expr.info + i ;
 | |
|     info->function = (S4OPERATOR S4PTR *)v4functions[info->function_i].function_ptr ;
 | |
|   }
 | |
| 
 | |
|   p4->expr.len_eval += 1 ;
 | |
|   if ( code_base->expr_buf_len < (unsigned)p4->expr.len_eval )
 | |
|     if ( u4alloc_again( code_base, &code_base->expr_work_buf, &code_base->expr_buf_len, p4->expr.len_eval ) == e4memory )
 | |
|       return -1 ;
 | |
| 
 | |
|   p4->expr.len = (int)(length[0]) ;
 | |
|   p4->expr.type = types[0] ;
 | |
|   return 0 ;
 | |
| }
 | |
| 
 | |
| int e4add_constant( E4PARSE *p4, int i_functions, void *cons_ptr, unsigned cons_len )
 | |
| {
 | |
|   E4INFO *info ;
 | |
| 
 | |
|   info = e4function_add( &p4->expr, i_functions ) ;
 | |
|   if ( info == 0 )
 | |
|     return -1 ;
 | |
|   info->i1 = p4->constants.pos ;
 | |
|   info->len = cons_len ;
 | |
|   return s4stack_push_str( &p4->constants, cons_ptr, (int) cons_len ) ;
 | |
| }
 | |
| 
 | |
| E4INFO *e4function_add( EXPR4 *expr, int i_functions )
 | |
| {
 | |
|   E4INFO *info ;
 | |
| 
 | |
|   if ( (unsigned)((expr->info_n+1)*sizeof(E4INFO)) > expr->code_base->expr_buf_len )
 | |
|     if ( u4alloc_again( expr->code_base, &expr->code_base->expr_work_buf, &expr->code_base->expr_buf_len, sizeof(E4INFO) * (expr->info_n+10) ) == e4memory )
 | |
|       return 0 ;
 | |
| 
 | |
|   info = (E4INFO *)expr->code_base->expr_work_buf + expr->info_n++ ;
 | |
| 
 | |
|   info->function_i = i_functions ;
 | |
|   info->num_parms = v4functions[i_functions].num_parms ;
 | |
|   if ( info->num_parms < 0 )
 | |
|     info->num_parms = 2 ;
 | |
|   info->function = (S4OPERATOR S4PTR *)v4functions[i_functions].function_ptr ;
 | |
|   return info ;
 | |
| }
 | |
| 
 | |
| void e4function_pop( EXPR4 *expr )
 | |
| {
 | |
|   expr->info_n-- ;
 | |
| }
 | |
| 
 | |
| EXPR4 *S4FUNCTION expr4parse( DATA4 *d4, char *expr_ptr )
 | |
| {
 | |
|   E4PARSE parse ;
 | |
|   char    ops[128] ;
 | |
|   char    constants[512] ;
 | |
|   int     rc, info_len, pos_constants ;
 | |
|   EXPR4 *express4 ;
 | |
| 
 | |
| #ifdef S4DEBUG
 | |
|   if ( d4 == 0 || expr_ptr == 0 )
 | |
|     e4severe( e4parm, E4_EXPR4PARSE ) ;
 | |
| #endif
 | |
| 
 | |
|   if ( d4->code_base->error_code < 0 )
 | |
|     return 0 ;
 | |
| 
 | |
|   if ( d4->code_base->expr_buf_len > 0 )
 | |
|     memset( d4->code_base->expr_work_buf, 0, d4->code_base->expr_buf_len ) ;
 | |
| 
 | |
|   memset( (void *)&parse, 0, sizeof(E4PARSE) ) ;
 | |
|   memset( ops, 0, sizeof(ops));
 | |
| 
 | |
|   parse.expr.data   = d4 ;
 | |
|   parse.expr.source = expr_ptr ;
 | |
|   parse.code_base   = d4->code_base ;
 | |
|   parse.expr.code_base = d4->code_base ;
 | |
| 
 | |
|   parse.op.ptr = ops ;
 | |
|   parse.op.len = sizeof(ops) ;
 | |
|   parse.op.code_base = d4->code_base ;
 | |
| 
 | |
|   parse.constants.ptr = constants ;
 | |
|   parse.constants.len = sizeof(constants) ;
 | |
|   parse.constants.code_base = d4->code_base ;
 | |
| 
 | |
|   s4scan_init( &parse.scan, expr_ptr ) ;
 | |
| 
 | |
|   rc = expr4parse_expr( &parse ) ;
 | |
|   if ( rc < 0 )
 | |
|     return 0 ;
 | |
| 
 | |
|   if ( s4stack_cur( &parse.op ) != E4NO_FUNCTION )
 | |
|   {
 | |
|     if( parse.code_base->expr_error )
 | |
|       e4( parse.code_base, e4complete, expr_ptr ) ;
 | |
|     return 0 ;
 | |
|   }
 | |
| 
 | |
|   parse.expr.info = (E4INFO *)parse.code_base->expr_work_buf ;
 | |
|   if ( e4massage( &parse ) < 0 )
 | |
|     return 0 ;
 | |
| 
 | |
|   info_len = parse.expr.info_n * sizeof(E4INFO) ;
 | |
|   pos_constants = sizeof(EXPR4) + info_len ;
 | |
| 
 | |
|   express4 = (EXPR4 *)u4alloc_free( d4->code_base, pos_constants + parse.constants.len + parse.scan.len + 1 ) ;
 | |
|   if ( express4 == 0 )
 | |
|     return 0 ;
 | |
| 
 | |
|   memcpy( (void *)express4, (void *)&parse.expr, sizeof(EXPR4) ) ;
 | |
| 
 | |
|   express4->data = d4 ;
 | |
|   express4->info = (E4INFO *)( express4 + 1 ) ;
 | |
|   express4->constants = (char *) express4 + pos_constants ;
 | |
|   express4->source = express4->constants + parse.constants.len ;
 | |
| 
 | |
|   memcpy( (void *)express4->info, parse.code_base->expr_work_buf, info_len ) ;
 | |
|   memcpy( express4->constants, constants, parse.constants.len ) ;
 | |
|   strcpy( express4->source, expr_ptr ) ;
 | |
| 
 | |
| #ifdef S4CLIPPER
 | |
|   express4->key_len = parse.expr.key_len ;
 | |
|   express4->key_dec = parse.expr.key_dec ;
 | |
| #endif
 | |
| 
 | |
|   return express4 ;
 | |
| }
 | |
| 
 | |
| /*    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  e4get_operator( E4PARSE *p4, int *op_return)
 | |
| {
 | |
|   char ch ;
 | |
|   int  op ;
 | |
| 
 | |
|   s4scan_range( &p4->scan, 1, ' ' ) ;
 | |
|   ch = s4scan_char(&p4->scan) ;
 | |
|   if ( ch==0 || ch==')' || ch==',')
 | |
|   {
 | |
|     *op_return = E4DONE ;
 | |
|     return(0) ; /* Done */
 | |
|   }
 | |
| 
 | |
|   op  = e4lookup( p4->scan.ptr+p4->scan.pos, -1, E4FIRST_OPERATOR, E4LAST_OPERATOR ) ;
 | |
|   if ( op < 0 )
 | |
|   {
 | |
|     if( p4->code_base->expr_error )
 | |
|       e4( p4->code_base, e4unrec_operator, p4->scan.ptr ) ;
 | |
|     return -1 ;
 | |
|   }
 | |
| 
 | |
|   p4->scan.pos += v4functions[op].name_len ;
 | |
|   *op_return = op ;
 | |
| 
 | |
|   return 0 ;
 | |
| }
 | |
| 
 | |
| /* e4lookup, searches 'v4functions' for an operator or function.
 | |
| 
 | |
|    str - the function name
 | |
|    str_len - If 'str_len' 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( char *str, int str_len, int start_i, int end_i )
 | |
| {
 | |
|   char u_str[9] ;  /* Maximum # of function name characters plus one. */
 | |
|   int  i ;
 | |
| 
 | |
|   u4ncpy( u_str, str, sizeof(u_str) ) ;
 | |
|   c4upper( u_str ) ;
 | |
| 
 | |
|   for( i=start_i; i<= end_i; i++)
 | |
|   {
 | |
|     if ( v4functions[i].code < 0 )
 | |
|       break ;
 | |
|     if ( v4functions[i].name == 0 )
 | |
|       continue ;
 | |
| #ifdef S4DEBUG
 | |
|     if ( v4functions[i].name_len >= (char)sizeof(u_str) )
 | |
|       e4severe( e4result, E4_EXPR4LOOKUP ) ;
 | |
| #endif
 | |
| 
 | |
|     if ( v4functions[i].name[0] == u_str[0] )
 | |
|       if( str_len == v4functions[i].name_len || str_len < 0 )
 | |
|         if (strncmp(u_str, v4functions[i].name, (size_t) v4functions[i].name_len) == 0)
 | |
|           return( i ) ;
 | |
|   }
 | |
|   return -1 ;
 | |
| }
 | |
| 
 | |
| static int op_to_expr( E4PARSE *p4 )
 | |
| {
 | |
|   E4INFO *info ;
 | |
| 
 | |
|   info = e4function_add( &p4->expr, s4stack_pop(&p4->op) ) ;
 | |
|   if ( info == 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   for(; s4stack_cur(&p4->op) == E4ANOTHER_PARM; )
 | |
|   {
 | |
|     s4stack_pop(&p4->op) ;
 | |
|     info->num_parms++ ;
 | |
|   }
 | |
| 
 | |
|   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  expr4parse_expr( E4PARSE *p4 )
 | |
| {
 | |
|   int  op_value, op_on_stack ;
 | |
| 
 | |
|   if ( expr4parse_value(p4) < 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   for(;;)
 | |
|   {
 | |
|     if ( e4get_operator(p4, &op_value) < 0 )
 | |
|       return -1 ;
 | |
|     if ( op_value == E4DONE )  /* Done */
 | |
|     {
 | |
|       while( s4stack_cur(&p4->op) != E4L_BRACKET
 | |
|             && s4stack_cur(&p4->op) != E4COMMA
 | |
|             && s4stack_cur(&p4->op) != E4NO_FUNCTION )
 | |
|         if( op_to_expr( p4 ) < 0 )
 | |
|           return -1 ;
 | |
|       return( 0) ;
 | |
|     }
 | |
| 
 | |
|     /* Everything with a higher or equal priority than 'op_value' must be
 | |
|        executed first. (equal because of left to right evaluation order)
 | |
|        Consequently, all high priority operators are sent to the result
 | |
|        stack.
 | |
|        */
 | |
|     while ( s4stack_cur(&p4->op) >= 0 )
 | |
|     {
 | |
|       op_on_stack = s4stack_cur(&p4->op) ;
 | |
|       if ( v4functions[op_value].priority <=
 | |
|           v4functions[op_on_stack].priority)
 | |
|       {
 | |
|         if ( op_value == op_on_stack && (int)v4functions[op_value].num_parms < 0)
 | |
|         {
 | |
|           /* If repeated AND or OR operator, combine them into one with an
 | |
|              extra paramter.  This makes the relate module optimization
 | |
|              algorithms easier. */
 | |
|           s4stack_pop(&p4->op) ;
 | |
|           s4stack_push_int( &p4->op, E4ANOTHER_PARM ) ;
 | |
|           break ;
 | |
|         }
 | |
|         else
 | |
|           if( op_to_expr( p4 ) < 0 )
 | |
|             return -1 ;
 | |
|       }
 | |
|       else
 | |
|         break ;
 | |
|     }
 | |
| 
 | |
|     s4stack_push_int( &p4->op, op_value) ;
 | |
| 
 | |
|     if ( expr4parse_value(p4) < 0 )
 | |
|       return -1 ;
 | |
|   }
 | |
| }
 | |
| 
 | |
| int  expr4parse_function( E4PARSE *p4, char *start_ptr, int f_len )
 | |
| {
 | |
|   int f_num, num_parms, info_i1, info_len ;
 | |
|   char ch ;
 | |
| #ifdef S4UNIX
 | |
|   double doub_val ;
 | |
| #endif
 | |
|   E4INFO *info ;
 | |
|   void *new_or_total_ptr = 0 ;
 | |
|   EXPR4CALC *calc ;
 | |
|   info_i1 = info_len = 0 ;
 | |
| 
 | |
|   if ( p4->code_base->error_code < 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   f_num = e4lookup( start_ptr, f_len, E4FIRST_FUNCTION, 0x7FFF) ;
 | |
|   if( f_num < 0 )
 | |
|   {
 | |
|     new_or_total_ptr = calc = expr4calc_lookup( p4->code_base, start_ptr, f_len ) ;
 | |
|     if( calc == 0 )
 | |
|     {
 | |
|       if( p4->code_base->expr_error )
 | |
|         e4( p4->code_base, e4unrec_function, p4->scan.ptr ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       f_num = E4CALC_FUNCTION ;
 | |
|       if( calc->total != 0 )
 | |
|       {
 | |
|         f_num = E4TOTAL ;
 | |
|         new_or_total_ptr = calc->total ;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   s4stack_push_int( &p4->op, E4L_BRACKET ) ;
 | |
|   p4->scan.pos++ ;
 | |
| 
 | |
|   num_parms = 0 ;
 | |
|   for(;;)
 | |
|   {
 | |
|     ch = s4scan_char( &p4->scan ) ;
 | |
|     if ( ch == 0 )
 | |
|     {
 | |
|       if( p4->code_base->expr_error )
 | |
|         e4( p4->code_base, e4right_missing, p4->scan.ptr ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
|     if ( ch == ')')
 | |
|     {
 | |
|       p4->scan.pos++ ;
 | |
|       break ;
 | |
|     }
 | |
| 
 | |
|     if ( expr4parse_expr(p4) < 0 )
 | |
|       return -1 ;
 | |
|     num_parms++ ;
 | |
| 
 | |
|     while( s4scan_char( &p4->scan ) <= ' ' &&
 | |
|           s4scan_char( &p4->scan ) >='\1')  p4->scan.pos++ ;
 | |
| 
 | |
|     if ( s4scan_char( &p4->scan ) == ')')
 | |
|     {
 | |
|       p4->scan.pos++ ;
 | |
|       break ;
 | |
|     }
 | |
|     if ( s4scan_char( &p4->scan ) != ',')
 | |
|     {
 | |
|       if( p4->code_base->expr_error )
 | |
|         e4( p4->code_base, e4comma_expected, p4->scan.ptr ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
|     p4->scan.pos++ ;
 | |
|   }
 | |
| 
 | |
|   s4stack_pop( &p4->op ) ;  /* pop the left bracket */
 | |
| 
 | |
|   if ( f_num == E4STR )
 | |
|   {
 | |
|     info_len= 10 ;
 | |
| 
 | |
|     if ( num_parms == 3  )
 | |
|     {
 | |
|       info = (E4INFO *) p4->code_base->expr_work_buf + p4->expr.info_n -1 ;
 | |
|       if ( info->function_i != E4DOUBLE )
 | |
|       {
 | |
|         if( p4->code_base->expr_error )
 | |
|           e4( p4->code_base, e4not_constant, p4->expr.source ) ;
 | |
|         return -1 ;
 | |
|       }
 | |
| #ifdef S4UNIX
 | |
|       memcpy( (void *)&doub_val, (p4->constants.ptr + info->i1), sizeof(double) ) ;
 | |
|       info_i1 = (int) doub_val ;
 | |
| #else
 | |
|       info_i1 = (int) *(double *) (p4->constants.ptr + info->i1) ;
 | |
| #endif
 | |
|       e4function_pop( &p4->expr ) ;
 | |
|       num_parms-- ;
 | |
|     }
 | |
|     if ( num_parms == 2  )
 | |
|     {
 | |
|       info = (E4INFO *)p4->code_base->expr_work_buf + p4->expr.info_n -1 ;
 | |
|       if ( info->function_i != E4DOUBLE )
 | |
|       {
 | |
|         if( p4->code_base->expr_error )
 | |
|           e4( p4->code_base, e4not_constant, p4->expr.source ) ;
 | |
|         return -1 ;
 | |
|       }
 | |
| #ifdef S4UNIX
 | |
|       memcpy( (void *)&doub_val, (p4->constants.ptr + info->i1), sizeof(double) ) ;
 | |
|       info_len = (int) doub_val ;
 | |
| #else
 | |
|       info_len = (int) *(double *) (p4->constants.ptr + info->i1) ;
 | |
| #endif
 | |
| 
 | |
|       e4function_pop( &p4->expr ) ;
 | |
|       num_parms-- ;
 | |
|     }
 | |
|     if ( info_len < 0 )
 | |
|       info_len = 10 ;
 | |
|     if ( info_len <= info_i1+1 )
 | |
|       info_i1 = info_len - 2 ;
 | |
|     if ( info_i1 < 0 )
 | |
|       info_i1 = 0 ;
 | |
|   }
 | |
|   if ( num_parms == 3  &&  f_num == E4SUBSTR || num_parms == 2  &&  f_num == E4LEFT )
 | |
|   {
 | |
|     info = (E4INFO *)p4->code_base->expr_work_buf + p4->expr.info_n -1 ;
 | |
|     if ( info->function_i != E4DOUBLE )
 | |
|     {
 | |
|       if( p4->code_base->expr_error )
 | |
|         e4( p4->code_base, e4not_constant, p4->expr.source ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
| #ifdef S4UNIX
 | |
|     memcpy( (void *)&doub_val, (p4->constants.ptr + info->i1), sizeof(double) ) ;
 | |
|     info_len = (int) doub_val ;
 | |
| #else
 | |
|     info_len = (int) *(double *) (p4->constants.ptr + info->i1) ;
 | |
| #endif
 | |
|     e4function_pop( &p4->expr ) ;
 | |
|     num_parms-- ;
 | |
|   }
 | |
|   if ( num_parms == 2  &&  f_num == E4SUBSTR )
 | |
|   {
 | |
|     info = (E4INFO *) p4->code_base->expr_work_buf + p4->expr.info_n -1 ;
 | |
|     if ( info->function_i != E4DOUBLE )
 | |
|     {
 | |
|       if( p4->code_base->expr_error )
 | |
|         e4( p4->code_base, e4not_constant, p4->expr.source ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
| #ifdef S4UNIX
 | |
|     memcpy( (void *)&doub_val, (p4->constants.ptr + info->i1), sizeof(double) ) ;
 | |
|     info_i1 = (int) doub_val ;
 | |
| #else
 | |
|     info_i1 = (int) *(double *) (p4->constants.ptr + info->i1) ;
 | |
| #endif
 | |
|     info_i1-- ;
 | |
|     e4function_pop( &p4->expr ) ;
 | |
|     num_parms-- ;
 | |
|   }
 | |
| 
 | |
|   if ( p4->code_base->error_code < 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   if ( num_parms != v4functions[f_num].num_parms  &&
 | |
|       (int)v4functions[f_num].num_parms >= 0 )
 | |
|   {
 | |
|     if( p4->code_base->expr_error )
 | |
|       e4describe( p4->code_base, e4num_parms, p4->scan.ptr, E4_NUM_PARMS, v4functions[f_num].name ) ;
 | |
|     return -1 ;
 | |
|   }
 | |
| 
 | |
|   info = e4function_add( &p4->expr, f_num ) ;
 | |
|   if ( info == 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   info->i1  = info_i1 ;
 | |
|   info->len = info_len ;
 | |
| 
 | |
|   info->num_parms = num_parms ;
 | |
|   if ( f_num == E4CALC_FUNCTION || f_num == E4TOTAL )
 | |
|     info->p1 = (char *) new_or_total_ptr ;
 | |
|   return 0 ;
 | |
| }
 | |
| 
 | |
| int expr4parse_value( E4PARSE *p4 )
 | |
| {
 | |
|   FIELD4 * field_ptr ;
 | |
|   char ch, *start_ptr, search_char ;
 | |
|   int  i_functions, len, i_function, save_pos ;
 | |
|   double d ;
 | |
|   E4INFO *expr, *info ;
 | |
|   DATA4 *base_ptr ;
 | |
|   char b_name[11], f_name[11] ;
 | |
| 
 | |
|   if ( p4->code_base->error_code < 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   s4scan_range( &p4->scan, ' ', ' ' ) ;
 | |
| 
 | |
|   /* expression */
 | |
| 
 | |
|   if ( s4scan_char( &p4->scan ) == '(')
 | |
|   {
 | |
|     p4->scan.pos++ ;
 | |
| 
 | |
|     s4stack_push_int( &p4->op, E4L_BRACKET) ;
 | |
|     if ( expr4parse_expr(p4) < 0 )  return( -1 ) ;
 | |
| 
 | |
|     while ( s4scan_char( &p4->scan ) <= ' ' &&
 | |
|            s4scan_char( &p4->scan ) != 0)   p4->scan.pos++ ;
 | |
| 
 | |
|     if ( s4scan_char( &p4->scan ) != ')' )
 | |
|     {
 | |
|       if( p4->code_base->expr_error )
 | |
|         e4( p4->code_base, e4right_missing, p4->scan.ptr ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
|     p4->scan.pos++ ;
 | |
|     s4stack_pop( &p4->op ) ;
 | |
|     return( 0 ) ;
 | |
|   }
 | |
| 
 | |
|   /* logical */
 | |
|   if ( s4scan_char( &p4->scan ) == '.' )
 | |
|   {
 | |
|     i_functions = e4lookup( p4->scan.ptr+p4->scan.pos, -1, E4FIRST_LOG, E4LAST_LOG ) ;
 | |
|     if ( i_functions >= 0 )
 | |
|     {
 | |
|       p4->scan.pos += v4functions[i_functions].name_len ;
 | |
| 
 | |
|       if ( strcmp( v4functions[i_functions].name, ".NOT." ) == 0 )
 | |
|       {
 | |
|         if ( expr4parse_value(p4) < 0 )  return( -1 ) ; /* One operand operation */
 | |
|         s4stack_push_int( &p4->op, i_functions ) ;
 | |
|         return 0 ;
 | |
|       }
 | |
| 
 | |
|       expr = e4function_add( &p4->expr, i_functions ) ;
 | |
|       if ( expr == 0 )
 | |
|         return -1 ;
 | |
|       return 0 ;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* string */
 | |
|   ch = s4scan_char( &p4->scan ) ;
 | |
|   if ( ch == '\'' || ch == '\"' || ch == '[' )
 | |
|   {
 | |
|     if ( ch == '[' )
 | |
|       search_char = ']' ;
 | |
|     else
 | |
|       search_char = ch ;
 | |
| 
 | |
|     p4->scan.pos++ ;
 | |
|     start_ptr = p4->scan.ptr + p4->scan.pos ;
 | |
| 
 | |
|     len = s4scan_search( &p4->scan, search_char ) ;
 | |
|     if ( s4scan_char( &p4->scan ) != search_char )
 | |
|       if ( len < 0 )
 | |
|       {
 | |
|         if( p4->code_base->expr_error )
 | |
|           e4( p4->code_base, e4unterminated, p4->scan.ptr ) ;
 | |
|         return -1 ;
 | |
|       }
 | |
|     p4->scan.pos++ ;
 | |
| 
 | |
|     if ( e4add_constant( p4, E4STRING, start_ptr, len ) < 0 )
 | |
|       return -1 ;
 | |
|     return 0 ;
 | |
|   }
 | |
| 
 | |
|   /* real */
 | |
|   ch = s4scan_char( &p4->scan ) ;
 | |
|   if ( ch >='0' && ch <='9' || ch == '-' || ch == '+' || ch == '.' )
 | |
|   {
 | |
|     start_ptr = p4->scan.ptr+p4->scan.pos ;
 | |
|     save_pos = p4->scan.pos ;
 | |
|     p4->scan.pos++ ;
 | |
|     len = 1 ;
 | |
| 
 | |
|     while( s4scan_char( &p4->scan ) >= '0' &&
 | |
|           s4scan_char( &p4->scan ) <= '9' ||
 | |
|           s4scan_char( &p4->scan ) == '.' )
 | |
|     {
 | |
|       if ( s4scan_char( &p4->scan ) == '.' )
 | |
|       {
 | |
|         if ( strnicmp( p4->scan.ptr+p4->scan.pos, ".AND.",5) == 0 ||
 | |
|             strnicmp( p4->scan.ptr+p4->scan.pos, ".OR.",4) == 0 ||
 | |
|             strnicmp( 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( s4scan_char( &p4->scan + 1 ) ) >= 'A' && toupper( s4scan_char( &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( s4scan_char( &p4->scan ) ) >= 'A' && toupper( s4scan_char( &p4->scan ) ) <= 'Z' )
 | |
|       p4->scan.pos = save_pos ;
 | |
|     else
 | |
|     {
 | |
|       d = c4atod( start_ptr, len ) ;
 | |
|       if ( e4add_constant( p4, E4DOUBLE, &d, sizeof(d) ) < 0 )
 | |
|         return -1 ;
 | |
|       return 0 ;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* function or field */
 | |
|   if (u4name_char(s4scan_char( &p4->scan )) )
 | |
|   {
 | |
|     start_ptr = p4->scan.ptr + p4->scan.pos ;
 | |
| 
 | |
|     for( len=0; u4name_char(s4scan_char( &p4->scan )); len++ )
 | |
|       p4->scan.pos++ ;
 | |
| 
 | |
|     s4scan_range( &p4->scan, (char)0, ' ' ) ;
 | |
| 
 | |
|     if ( s4scan_char( &p4->scan ) == '(' )
 | |
|       return expr4parse_function( p4, start_ptr, len ) ;
 | |
| 
 | |
|     base_ptr = 0 ;
 | |
| 
 | |
| #ifdef S4FOX
 | |
|     if ( s4scan_char( &p4->scan ) == '.' )
 | |
|     {  /* for fox, same as -> */
 | |
|       if ( len > 10 )
 | |
|         len = 10 ;
 | |
|       memmove( b_name, start_ptr, (size_t)len ) ;
 | |
|       b_name[len] = '\0' ;
 | |
| 
 | |
|       base_ptr = d4data( p4->code_base, b_name) ;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     if ( s4scan_char( &p4->scan ) == '-' )
 | |
|       if ( p4->scan.ptr[p4->scan.pos+1] == '>')
 | |
|       {
 | |
|         if ( len > 10 )
 | |
|           len = 10 ;
 | |
|         memmove( b_name, start_ptr, (size_t)len ) ;
 | |
|         b_name[len] = '\0' ;
 | |
| 
 | |
|         base_ptr = d4data( p4->code_base, b_name) ;
 | |
| 
 | |
|         if ( base_ptr == 0 )
 | |
|         {
 | |
|           if( p4->code_base->expr_error )
 | |
|             e4describe( p4->code_base, e4data_name, b_name, p4->scan.ptr, (char *) 0 ) ;
 | |
|           return -1 ;
 | |
|         }
 | |
|         p4->scan.pos++ ;
 | |
|       }
 | |
| 
 | |
| 
 | |
|     if ( base_ptr != 0 )
 | |
|     {
 | |
|       p4->scan.pos++ ;
 | |
| 
 | |
|       start_ptr = p4->scan.ptr + p4->scan.pos ;
 | |
|       for( len=0; u4name_char(s4scan_char( &p4->scan )); len++ )
 | |
|         p4->scan.pos++ ;
 | |
|     }
 | |
|     else
 | |
|       base_ptr = (DATA4 *) p4->expr.data ;
 | |
| 
 | |
|     if ( len <= 10)
 | |
|     {
 | |
|       memmove( f_name, start_ptr, (size_t) len ) ;
 | |
|       f_name[len] = 0 ;
 | |
|       field_ptr = d4field( base_ptr, f_name ) ;
 | |
|       if ( field_ptr == 0 )
 | |
|         return -1 ;
 | |
| 
 | |
| #ifdef S4CLIPPER
 | |
|       p4->expr.key_len = field_ptr->len ;
 | |
|       p4->expr.key_dec = field_ptr->dec ;
 | |
| #endif
 | |
| 
 | |
|       i_function = 0 ;
 | |
|       switch( field_ptr->type )
 | |
|       {
 | |
|       case 'N':
 | |
|       case 'F':
 | |
|         i_function = E4FIELD_NUM_S ;
 | |
|         break ;
 | |
|       case 'C':
 | |
|         i_function = E4FIELD_STR ;
 | |
|         break ;
 | |
|       case 'D':
 | |
|         i_function = E4FIELD_DATE_S ;
 | |
|         break ;
 | |
|       case 'L':
 | |
|         i_function = E4FIELD_LOG ;
 | |
|         break ;
 | |
|       case 'M':
 | |
| #ifdef S4MEMO_OFF
 | |
|         return e4( p4->code_base, e4not_memo, E4_EXPR4PV ) ;
 | |
| #else
 | |
|         i_function = E4FIELD_MEMO ;
 | |
|         break ;
 | |
| #endif
 | |
|       default:
 | |
|         if( p4->code_base->expr_error )
 | |
|           e4( p4->code_base, e4type_sub, E4_TYPE_UFT ) ;
 | |
|         return -1 ;
 | |
|       }
 | |
| 
 | |
|       info = e4function_add( &p4->expr, i_function ) ;
 | |
|       if ( info == 0 )
 | |
|         return -1 ;
 | |
|       info->field_ptr = field_ptr ;
 | |
|       info->p1 = (char *) &base_ptr->record ;
 | |
|       info->i1 = field_ptr->offset ;
 | |
| 
 | |
|       return 0 ;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if( p4->code_base->expr_error )
 | |
|     e4( p4->code_base, e4unrec_value, p4->scan.ptr ) ;
 | |
|   return -1 ;
 | |
| }
 | |
| 
 | |
| int s4stack_pop( S4STACK *s4 )
 | |
| {
 | |
|   int ret_value ;
 | |
| 
 | |
|   ret_value = s4stack_cur(s4) ;
 | |
| 
 | |
|   if ( s4->pos >= sizeof(int) )
 | |
|     s4->pos -= sizeof(int) ;
 | |
|   return ret_value ;
 | |
| }
 | |
| 
 | |
| int s4stack_cur( S4STACK *s4 )
 | |
| {
 | |
|   int pos, cur_data ;
 | |
| 
 | |
|   if ( s4->pos < sizeof(int) )
 | |
|     return E4NO_FUNCTION ;
 | |
|   pos = s4->pos - sizeof(int) ;
 | |
|   memcpy( (void *)&cur_data, s4->ptr+pos, sizeof(int) ) ;
 | |
|   return cur_data ;
 | |
| }
 | |
| 
 | |
| int s4stack_push_int( S4STACK *s4, int i )
 | |
| {
 | |
|   return s4stack_push_str( s4, &i, sizeof(i)) ;
 | |
| }
 | |
| 
 | |
| int s4stack_push_str( S4STACK *s4, void *p, int len )
 | |
| {
 | |
|   char *old_ptr ;
 | |
| 
 | |
|   if ( s4->code_base->error_code < 0 )
 | |
|     return -1 ;
 | |
| 
 | |
|   if ( s4->pos+len > s4->len )
 | |
|   {
 | |
|     old_ptr = s4->ptr ;
 | |
|     if ( ! s4->do_extend )
 | |
|       s4->ptr = 0 ;
 | |
|     else
 | |
|       s4->ptr = (char *)u4alloc_free( s4->code_base, s4->len + 256 ) ;
 | |
|     if ( s4->ptr == 0 )
 | |
|     {
 | |
|       s4->ptr = old_ptr ;
 | |
|       if( s4->code_base->expr_error )
 | |
|         e4( s4->code_base, e4memory, 0 ) ;
 | |
|       return -1 ;
 | |
|     }
 | |
|     memcpy( s4->ptr, old_ptr, s4->len ) ;
 | |
|     u4free( old_ptr ) ;
 | |
|     s4->len += 256 ;
 | |
| 
 | |
|     return  s4stack_push_str( s4, p, len ) ;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     memcpy( s4->ptr+s4->pos, p, len ) ;
 | |
|     s4->pos += len ;
 | |
|   }
 | |
|   return 0 ;
 | |
| }
 | |
| 
 | |
| 
 | |
| char s4scan_char( S4SCAN *s4 )
 | |
| {
 | |
|   if ( s4->pos >= s4->len )
 | |
|     return 0 ;
 | |
|   return s4->ptr[s4->pos] ;
 | |
| }
 | |
| 
 | |
| void s4scan_init( S4SCAN *s4, char *p )
 | |
| {
 | |
|   s4->ptr = p ;
 | |
|   s4->pos = 0 ;
 | |
|   s4->len = strlen(p) ;
 | |
| }
 | |
| 
 | |
| int s4scan_range( S4SCAN *s4, int start_char, int end_char )
 | |
| {
 | |
|   int count ;
 | |
| 
 | |
|   for ( count = 0; s4->pos < s4->len; s4->pos++, count++ )
 | |
|     if ( s4->ptr[s4->pos] < start_char || s4->ptr[s4->pos] > end_char )
 | |
|       return count ;
 | |
|   return count ;
 | |
| }
 | |
| 
 | |
| int s4scan_search( S4SCAN *s4, char search_char )
 | |
| {
 | |
|   int count ;
 | |
| 
 | |
|   for ( count = 0; s4->pos < s4->len; s4->pos++, count++ )
 | |
|     if ( s4->ptr[s4->pos] == search_char )
 | |
|       return count ;
 | |
|   return count ;
 | |
| }
 | |
| 
 | |
| #ifdef S4VB_DOS
 | |
| 
 | |
| EXPR4 *expr4parse_v( DATA4 *d4, char *expr )
 | |
| {
 | |
|   return expr4parse( d4, c4str(expr) ) ;
 | |
| }
 | |
| 
 | |
| #endif
 |