/* r4total.c (c)Copyright Sequiter Software Inc., 1991-1994. All rights reserved. */ #include "d4all.h" #include /* resets the totals values */ void S4FUNCTION total4value_reset( TOTAL4 *t4 ) { t4->low = 1.7 * pow(10.0, 308.0); t4->high = -1.7 * pow(10.0, 308.0); t4->count = 0; t4->total = 0.0; } /* frees the TOTAL4 related memory, then deletes the calculation used to create the total */ void S4FUNCTION total4free( TOTAL4 *total ) { if( total->last_reset_value ) { u4free( total->last_reset_value ); total->last_reset_value = NULL; } if( total->reset_expression ) { expr4free( total->reset_expression ); total->reset_expression = NULL; } if( total->last_add_value ) { u4free( total->last_add_value ); total->last_add_value = NULL; } if( total->add_condition ) { expr4free( total->add_condition ); total->add_condition = NULL; } expr4calc_delete( total->calc_ptr ); } /* creates a total */ TOTAL4 * S4FUNCTION total4create( REPORT4 *r4, char *name, char *expr_src, int total_type, char *reset_expr_src ) { EXPR4 *expr, *rexpr; TOTAL4 *t4; if( !r4 ) return NULL; if( !name || name[0] == '\0' || !expr_src ) { e4describe( r4->code_base, e4parm, E4_REP_TCREATEVAL, 0, 0 ); return NULL; } /* parse the expression */ expr = expr4parse( r4->relate->data, expr_src ); if( !expr ) { e4describe( r4->code_base, e4total_create, E4_REP_TEXPR, 0, 0 ); return NULL; } /* allocate the TOTAL4 structure */ t4 = (TOTAL4 *)mem4create_alloc( r4->code_base, &r4->code_base->total_memory, 5, sizeof(TOTAL4), 5, 0 ); if( !t4 ) { e4describe( r4->code_base, e4total_create, E4_REP_TMEM, 0, 0 ); expr4free( expr ); return NULL; } /* create the calculation based on the expression */ t4->calc_ptr = expr4calc_create( r4->code_base, expr, name ); if( !t4->calc_ptr ) { e4describe( r4->code_base, e4total_create, E4_REP_TCALC, 0, 0 ); u4free( t4 ); expr4free( expr ); return NULL; } /* set the flags and pointers */ t4->calc_ptr->total = t4; t4->report = r4; t4->total_type = total_type; /* set the totals reset expression */ if( reset_expr_src && reset_expr_src[0] != '\0' ) { rexpr = expr4parse( r4->relate->data, reset_expr_src ); if( !rexpr ) { e4describe( r4->code_base, e4total_create, E4_REP_TREXPR, 0, 0 ); expr4free( expr ); u4free( t4 ); return NULL; } t4->reset_expression = rexpr; } l4add( &r4->code_base->total_list, t4 ); total4value_reset( t4 ); return t4; } /* This function is used for evaluating look ahead totals, it skips ahead through the records incrementing the total appropriately until the reset condition is met */ void total4evaluate_lookahead( PTOTAL4 total ) { long reccount = 0; int flag, len, addflag; char *ptr; double tvalue; if( !total->reset_expression && total->donce ) return; total->donce = 1; addflag = 1; /* check the conditional add */ if( total->add_condition ) { addflag = 0; if( total->logcon == 0 ) { len = expr4vary( total->add_condition, &ptr ); if( memcmp( total->last_add_value, ptr, len ) != 0 ) { memset( total->last_add_value, 0, len+1 ); memcpy( total->last_add_value, ptr, len ); addflag = 1; } } else { if( expr4true( total->add_condition ) ) addflag = 1; } } /* increment the total for the current record */ if( addflag == 1 ) { tvalue = expr4double( total->calc_ptr->expr ) ; total->total += tvalue ; total->count += 1 ; if ( tvalue < total->low ) total->low = tvalue ; if( tvalue > total->high ) total->high = tvalue ; } /* start going through the records */ flag = 1; while( flag ) { if( relate4skip( total->report->relate, 1L ) != 0 ) { reccount++; break; } reccount++; /* if this total has a reset expression */ if( total->reset_expression ) { len = expr4vary( total->reset_expression, &ptr ); /* if the reset condition is not met */ if( memcmp( ptr, total->last_reset_value, len ) == 0 ) { addflag = 1; /* check for a conditional total */ if( total->add_condition ) { addflag = 0; if( total->logcon == 0 ) { len = expr4vary( total->add_condition, &ptr ); if( memcmp( total->last_add_value, ptr, len ) != 0 ) { memset( total->last_add_value, 0, len+1 ); memcpy( total->last_add_value, ptr, len ); addflag = 1; } } else { if( expr4true( total->add_condition ) ) addflag = 1; } } /* increment the total */ if( addflag == 1 ) { tvalue = expr4double( total->calc_ptr->expr ) ; total->total += tvalue ; total->count += 1 ; if ( tvalue < total->low ) total->low = tvalue ; if( tvalue > total->high ) total->high = tvalue ; } } else /* if the reset condition is met */ { flag = 0; } } else /* if no reset condition */ { addflag = 1; /* check for a conditional total */ if( total->add_condition ) { addflag = 0; if( total->logcon == 0 ) { len = expr4vary( total->add_condition, &ptr ); if( memcmp( total->last_add_value, ptr, len ) != 0 ) { memset( total->last_add_value, 0, len+1 ); memcpy( total->last_add_value, ptr, len ); addflag = 1; } } else { if( expr4true( total->add_condition ) ) addflag = 1; } } /* increment the total for the current record */ if( addflag == 1 ) { tvalue = expr4double( total->calc_ptr->expr ) ; total->total += tvalue ; total->count += 1 ; if ( tvalue < total->low ) total->low = tvalue ; if( tvalue > total->high ) total->high = tvalue ; } } } /* skip back the appropriate number of records */ relate4skip( total->report->relate, (long)(-1 * reccount) ); } /* updates the totals internals */ void total4value_update( TOTAL4 *total ) { double tvalue; int len, flag = 1; char *ptr; int addflag; /* check for a reset on the total */ if( total->reset_expression ) { len = expr4vary( total->reset_expression, &ptr ); if( (flag = memcmp(total->last_reset_value, ptr, len)) != 0 ) { memset( total->last_reset_value, 0, len+1 ); memcpy( total->last_reset_value, ptr, len ); total->low = 1.7 * pow( 10,308 ) ; total->high = -1.7 * pow( 10,308 ) ; total->total = 0.0 ; total->count = 0; } } /* for non-lookahead totals */ if( !total->lookahead ) { addflag = 1; /* check for conditional total */ if( total->add_condition ) { addflag = 0; if( total->logcon == 0 ) { len = expr4vary( total->add_condition, &ptr ); if( memcmp( total->last_add_value, ptr, len ) != 0 ) { memset( total->last_add_value, 0, len+1 ); memcpy( total->last_add_value, ptr, len ); addflag = 1; } } else { if( expr4true( total->add_condition ) ) addflag = 1; } } /* increment the total */ if( addflag ) { tvalue = expr4double( total->calc_ptr->expr ) ; total->total += tvalue ; total->count += 1 ; if( tvalue < total->low ) total->low = tvalue ; if( tvalue > total->high ) total->high = tvalue ; } } /* evaluate the lookahead */ if( total->lookahead && flag != 0 ) { total4evaluate_lookahead( total ); } } /* returns a pointer to the TOTAL4 with the given name */ TOTAL4 * S4FUNCTION total4lookup( REPORT4 *report, char *name ) { TOTAL4 *total_on ; if( !report ) return NULL; if( !name || name[0] == '\0' ) { e4describe( report->code_base, e4parm, E4_REP_TLKP, 0, 0 ); return NULL; } total_on = (TOTAL4 *) l4first( &report->code_base->total_list ); while(total_on) { if ( strcmp( name, total_on->calc_ptr->name ) == 0 ) return total_on ; total_on = (TOTAL4 *) l4next( &report->code_base->total_list,total_on); } return NULL ; } /* this function is used when checking whether objects are dependant on a certain total or calculation, also in deleting any dependant objects. If the function is being used to check for dependancies (delflag = 0) it simply returns 1 at the first dependant object found. If delflag = 1 any dependant objects are delted */ int report4checkObjExpr( POBJ4 obj, int delflag ) { EXPR4CALC *calc_on; POBJ4 obj_on, obj_next; EXPR4 *expr; CODE4 *cb; int rc; cb = obj->area->report->code_base; obj_on = (POBJ4)l4first( &obj->contained ); while( obj_on ) { obj_next = (POBJ4)l4next( &obj->contained, obj_on ); rc = report4checkObjExpr( obj_on, delflag ); if( rc == 1 ) return rc; obj_on = obj_next; } switch( obj->obj_type_num ) { case obj4type_expr: expr = expr4parse( obj->area->report->relate->data, expr4source((EXPR4 *)obj->data) ); if( expr ) { expr4free( expr ); } else { if( delflag ) obj4delete( obj ); else return 1; } break; case obj4type_total: rc = 0; calc_on = (EXPR4CALC *)l4first( &cb->calc_list ); while( calc_on ) { if( calc_on == ((PTOTAL4)obj->data)->calc_ptr ) { rc = 1; calc_on = NULL; } else calc_on = (EXPR4CALC *)l4next( &cb->calc_list, calc_on ); } if( rc == 0 ) { if( delflag ) { obj->data = NULL; obj4free( obj ); } else return 1; } break; case obj4type_calc: rc = 0; calc_on = (EXPR4CALC *)l4first( &cb->calc_list ); while( calc_on ) { if( calc_on == (EXPR4CALC *)obj->data ) { rc = 1; calc_on = NULL; } else calc_on = (EXPR4CALC *)l4next( &cb->calc_list, calc_on ); } if( rc == 0 ) { if( delflag ) obj4delete( obj ); else return 1; } break; } return 0; } /* USED to delete a calc/total from the report */ int S4FUNCTION report4deleteCalc( PREPORT4 report, EXPR4CALC S4PTR *del_calc ) { POBJ4 obj_on, obj_next; EXPR4 *expr; LIST4 temp_calc_list; CODE4 *code_base; PGROUP4 group_on; PAREA4 area_on; EXPR4CALC *calc_on, *calc_next; int calc_transfered = 1, expr_error, rc = 0; if( report == NULL || del_calc == NULL ) { return -1; } code_base = report->code_base; /* separate the calculations so that a temporary list contains all calculations dependant on the calculation to be deleted */ memcpy( &temp_calc_list, &code_base->calc_list, sizeof(temp_calc_list) ); memset( &code_base->calc_list, 0, sizeof(code_base->calc_list) ); if( l4seek( &temp_calc_list, del_calc ) != 0 ) l4remove( &temp_calc_list, del_calc ); expr_error = code_base->expr_error; code_base->expr_error = 0; while( calc_transfered ) { calc_transfered = 0; calc_on = (EXPR4CALC *)l4first( &temp_calc_list ); while( calc_on ) { calc_next = (EXPR4CALC *)l4next( &temp_calc_list, calc_on ); expr = expr4parse( calc_on->expr->data, expr4source(calc_on->expr) ); if( expr ) { expr4free( expr ); l4remove( &temp_calc_list, calc_on ); l4add( &code_base->calc_list, calc_on ); calc_transfered = 1; } calc_on = calc_next; } } l4add( &code_base->calc_list, del_calc ); expr4calc_delete( del_calc ); calc_on = (EXPR4CALC *)l4pop( &temp_calc_list ); while( calc_on ) { l4add( &code_base->calc_list, calc_on ) ; expr4calc_delete( calc_on ) ; calc_on = (EXPR4CALC *)l4pop( &temp_calc_list ); } /* Now check on all the objects in the report */ /* start with the page header and footer */ group_on = report->page_header_footer; if( group_on ) { area_on = (PAREA4)l4first( &group_on->header_areas ); while( area_on ) { obj_on = (POBJ4)l4first( &area_on->objects ); while( obj_on ) { obj_next = (POBJ4)l4next( &area_on->objects, obj_on ); rc = report4checkObjExpr( obj_on, 1 ); if( rc == 1 ) obj_on = NULL; else obj_on = obj_next; } if( rc == 1 ) area_on = NULL; else area_on = (PAREA4)l4next( &group_on->header_areas, area_on ); } area_on = (PAREA4)l4first( &group_on->footer_areas ); while( area_on ) { obj_on = (POBJ4)l4first( &area_on->objects ); while( obj_on ) { obj_next = (POBJ4)l4next( &area_on->objects, obj_on ); rc = report4checkObjExpr( obj_on, 1 ); if( rc == 1 ) obj_on = NULL; else obj_on = obj_next; } if( rc == 1 ) area_on = NULL; else area_on = (PAREA4)l4next( &group_on->footer_areas, area_on ); } } group_on = (PGROUP4)l4first( &report->groups ); if( rc == 1 ) group_on = NULL; while( group_on ) { area_on = (PAREA4)l4first( &group_on->header_areas ); while( area_on ) { obj_on = (POBJ4)l4first( &area_on->objects ); while( obj_on ) { obj_next = (POBJ4)l4next( &area_on->objects, obj_on ); rc = report4checkObjExpr( obj_on, 1 ); if( rc == 1 ) obj_on = NULL; else obj_on = obj_next; } if( rc == 1 ) area_on = NULL; else area_on = (PAREA4)l4next( &group_on->header_areas, area_on ); } area_on = (PAREA4)l4first( &group_on->footer_areas ); while( area_on ) { obj_on = (POBJ4)l4first( &area_on->objects ); while( obj_on ) { obj_next = (POBJ4)l4next( &area_on->objects, obj_on ); rc = report4checkObjExpr( obj_on, 1 ); if( rc == 1 ) obj_on = NULL; else obj_on = obj_next; } if( rc == 1 ) area_on = NULL; else area_on = (PAREA4)l4next( &group_on->footer_areas, area_on ); } if( rc == 1 ) group_on = NULL; else group_on = (PGROUP4)l4next( &report->groups, group_on ); } report->code_base->expr_error = expr_error; return 0; } /* SEE THE CODEREPORTER MANUAL */ int S4FUNCTION total4addCondition( PTOTAL4 total, char *add_condition_src, int logcon ) { EXPR4 *expr; if( !total || !add_condition_src || logcon < 0 ) return -1; if( total->report == NULL ) return -1; expr = expr4parse( total->report->relate->data, add_condition_src ); if( expr ) { if( logcon && expr4type(expr) != r4log ) return -1; if( total->add_condition ) expr4free( total->add_condition ); total->add_condition = expr; if( total->last_add_value ) { u4free( total->last_add_value ); total->last_add_value = NULL; } total->logcon = logcon; return 0; } else e4set( total->report->code_base, 0 ); return -1; }