/************************************************************************* * Copyright (C) 1995 Embedded Solutions * All rights reserved * * file: src\report.c * * purpose: PREFIX - * * functions * report - Report menu * pri_team - Print in team order * pri_leg - Print in given leg finishing time * p_place - Print place information * p_team - Print team information * pri_eleg - Print on elapsed times for given leg * pe_place - Print place and elapsed time information * pe_team - Print team and elapsed time information * pri_final - Print final results * pri_interim - Print interim results * print_class_header - Print a class header * print_class_stats - Generate the class stats * print_legend - Print the legend * pi_place - Return place data * pr_place - Return place data * ck_data - Check data for bad times * srt_place - Update placing information * do_big_sort - Main sort routine for final data * sort - Sort in memory buffer * sort_comp - qsort comparison function * load - load report data into memory * gen_stats - Generate all the stats * * programmer: David Purdie * * revision date by reason * e388 11-Oct-88 Option in the final printout to only * produce the main result sheet. The leg * placing printout is not produced. * * Changes to the display format of unknown * times of disqualified teams. Only affects * the leg-printouts. * Disqualified teams show as -- -- -- * Otherwise they show as ** ** ** * or a valid time. * * e339 31-Oct-88 DDP Added the "Interim Report" facility * 00.0 27/01/95 DDP Tidies up the program and formatted the file * 00.1 06-sep-02 DDP Added support for HTML report generation * **************************************************************************/ #include #if defined(HI_TECH_C) || defined(__TURBOC__) #include #endif #include "consts.h" #include "structs.h" #include "proto.h" void pri_awards_html(void); void pri_awards(void); void pri_master_index(void); char *placing ( int place ); void pri_name_index(void); void pri_name_index_body( void ); void pri_all_reports (void ); void pri_leg_body(int leg); void pri_eleg_body(int leg); void pri_csv_data ( void ); menu_table rpt_menu[] = { { '1', "Print team order", pri_team }, { '2', "Print end leg times", pri_leg }, { '3', "Print elapsed leg times", pri_eleg }, { '4', "Print final results", pri_final }, { '5', "Print final results(All-HTML)", pri_final_html }, { '6', "Print Interim results", pri_interim }, { '7', "Update event and class placings", srt_place }, { '8', "Display summary information", display_summary }, { '9', "Print summary information", pri_summary }, { 'a', "Print Awards only", pri_awards_html }, { 'b', "Print Master Index only", pri_master_index }, { 'c', "Print Name Index only", pri_name_index }, { 'e', "Export CSV Report Data", pri_csv_data }, { 'z', "Print all reports", pri_all_reports }, #if defined(HI_TECH_C) || defined(__TURBOC__) { 'S', "MS-DOS system", ms_system }, #endif { 'q', "Return to main menu", 0 }, { '\0' } }; #define MAX_PLACE 11 char * place_text[] = { "Zero'th", "First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth", "Ninth", "Tenth", "Eleventh" }; int sort_leg; int sort_mode; report_type report_html = text; bool report_all = FALSE; /* Parameters used by the sort routine to govern its actions */ #define S_L 1 /* Elasped times */ #define S_LE 2 /* Leg end time */ #define S_LC 3 /* Elapsed times per class */ #define S_LEC 4 /* Leg end time per class */ #define S_FIN 5 /* Sort on finish time at given leg */ #define S_TEAM 6 /* Sort on team order */ #define S_CLASS 7 /* Sort on class/team order */ /* ** Various checking modes */ #define C_ELAPSED 1 /* Check elapsed times */ #define C_END 2 /* Check end times */ #define C_DISQUAL 3 /* Check disqualified teams */ /* ** Data */ ty_s_data *sort_data = 0; /* pointer to memory */ ty_s_aux *sort_aux = 0; /* pointer to aux sort info */ ty_s_namedata *sort_name_data = 0; /* pointer to name info */ unsigned sort_num; /* Number in the array */ unsigned sort_num_data; /* Number in the array */ /* ** A structure to hold statistical information */ typedef struct { int team[MAX_LEGS + 1][MAX_CLASS + 1]; struct { int team[MAX_LEGS + 1][MAX_CLASS + 1]; time_t time[MAX_LEGS + 1][MAX_CLASS + 1]; } fast; time_t average[MAX_LEGS + 1][MAX_CLASS + 1]; } ty_stats; ty_stats stats; /* Holds statistics */ /*======================================================================== * * Report menu * * Purpose: * This function is called to produce the "Report Menu" * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void report(void) { report_html = text; if( load_report_data() ) do_menu( "Report generation", "Select option", rpt_menu ); if( sort_data ) free( ( char * ) sort_data ); if( sort_aux ) free( ( char * ) sort_aux ); if ( sort_name_data ) free( ( char * ) sort_name_data ); sort_data = ( ty_s_data * ) 0; sort_aux = ( ty_s_aux * ) 0; sort_name_data = ( ty_s_namedata * ) 0; } /*======================================================================== * * Print in team order * * Purpose: * This function is called to Print in team order * This function may also be used to create an HTML suite of files * within the result set * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_team(void) { int i, k; cur( 0, 5 ); printf( "Team information - in team order\n" ); printf( "\nPrinting team names\n" ); flush_out(); if( !open_printer( "", "name", 132, report_html, "Team Names" ) ) return; /* * Print out the data * Print out the header */ print( "\n" ); print_underline( TRUE ); print( "%-*s %-*s %-*s", MAX_TM_NAME + 5, "Entry number and name", LEN_CLASS_NAME, "Category", config.num_countries == 0 ? 1 : LEN_CNTRY_NAME, config.num_countries == 0 ? "" : "Country" ); for( k = 0; k < MAX_MEMB; k++ ) { print( " %-*s", MAX_PERSON_NAME, config.leg_name[k] ? config.leg_name[k] : "Competitor" ); } print_underline( FALSE ) ; print( "\n" ); for( i = config.min_team; i <= config.max_team; i++ ) { if( valid_field( i ) && g_record( i, &team_buf ) ) { /* ** If printing an HTML report then we need to mark ** the entry with a reference so that we can link to it */ if ( report_html == html ) { print( "",team_buf.numb ); print( "" ); } /* ** Basic information ** - Team number - with Xref back to full result ** - Full team name ** - Full categoray name - with Xref to category results ** - Country name */ if ( report_html == html ) print( "", url_encode(p_filename(filebase, "finish" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); if ( report_html == html ) print( "" ); print( " %-*s ", MAX_TM_NAME, team_buf.name ); if ( report_html == html ) print( "",url_encode(p_filename(filebase, config.team_class[team_buf.class - 1].abr ,"html")), team_buf.numb ); print( "%-*s", LEN_CLASS_NAME, team_buf.class == 0 ? "" : config.team_class[team_buf.class - 1].full_name ); if ( report_html == html ) print( "" ); print( " %-*s", config.num_countries == 0 ? 1 : LEN_CNTRY_NAME, config.num_countries == 0 || team_buf.country == 0 ? "" : config.country_name[team_buf.country - 1].full_name ); for( k = 0; k < MAX_MEMB; k++ ) print( " %-*s", MAX_PERSON_NAME, team_buf.members[k].name ); print( "\n" ); } } close_printer(); } /*======================================================================== * * Print in name order * * Purpose: * This function is called to print a list of all known competitors * This function may also be used to create an HTML suite of files * within the result set * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_name_index( void ) { cur( 0, 5 ); printf( "Team Member information - in name order\n" ); printf( "\nPrinting competitor names\n" ); flush_out(); pri_name_index_body(); printf( "Found %d names\n", sort_num_data ); printf( "\nAny key to continue" ); getinp(); } /*======================================================================== * * Print in name order * * Purpose: * This function is called to print a list of all known competitors * This function may also be used to create an HTML suite of files * within the result set * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_name_index_body( void ) { ty_s_namedata *ptr; unsigned num; int i,k; int num_names; /* ** Determine the number of names to allow for * Based on the total number of teams */ num = config.max_team - config.min_team + 1 ; num *= MAX_MEMB; sort_name_data = ( ty_s_namedata * ) calloc ( num , sizeof( ty_s_namedata ) ); if( sort_name_data == 0 ) { printf( "\n\nError in allocating memory\n" ); sleep( 5 ); return; } /* ** Read all teams an extract name information */ ptr = sort_name_data; for( i = config.min_team; i <= config.max_team; i++ ) { if( valid_field( i ) && g_record( i, &team_buf ) ) { num_names = 0; for( k = 0; k < MAX_MEMB; k++ ) { if ( team_buf.members[k].name[0] ) { ptr->team = i; ptr->leg = k; ptr->class = team_buf.class; strncpy( ptr->name,team_buf.members[k].name, sizeof(team_buf.members[k].name)); ptr++; num_names++; } } if ( num_names == 0 ) { ptr->team = i; ptr->leg = 0; ptr->class = team_buf.class; strncpy( ptr->name,team_buf.name, sizeof(team_buf.members[k].name)); ptr++; } } } sort_num_data = ptr - sort_name_data; /* ** Now stort the entries by name:team:leg */ qsort( ( char * ) sort_name_data, sort_num_data, sizeof( ty_s_namedata ), sort_comp_cname ); /* ** Now generate the report */ if( !open_printer( "", "competitor", 80, report_html, "Competitor Names" ) ) return; /* * Print out the data * Print out the header */ print( "\n" ); print_underline( TRUE ); print( "%-*s %-*s %-*s %-*s", MAX_TM_NAME + 5, "Competitor name", 6, "Leg", 5, "Team", LEN_CLASS_NAME, "Category" ); print_underline( FALSE ) ; print( "\n" ); ptr = sort_name_data; for( k = 1; k <= sort_num_data; k++, ptr++ ) { print( "%-*s", MAX_TM_NAME + 5, ptr->name ); print( " " ); if ( report_html == html ) print( "", url_encode(p_filename(filebase, "finish" ,"html")), ptr->team ); print( "%-*d", 6, ptr->leg + 1 ); if ( report_html == html ) print( "" ); print( " " ); if ( report_html == html ) print( "", url_encode(p_filename(filebase, "name" ,"html")), ptr->team ); print( "%-*d", 5, ptr->team ); if ( report_html == html ) print( "" ); print( " " ); if ( report_html == html ) print( "",(p_filename(filebase, config.team_class[ptr->class - 1].abr ,"html")), ptr->team ); print( "%-*s", LEN_CLASS_NAME, ptr->class == 0 ? "" : config.team_class[ptr->class - 1].abr ); if ( report_html == html ) print( "" ); print( " " ); if ( ptr->multi ) print( "* "); print( "\n" ); } print_legend( -1, 0 ); close_printer(); } /*======================================================================== * * Print in given leg finishing time * * Purpose: * This function is called to Print in given leg finishing time * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_leg(void) { int leg = 0; /* * This function is used to provide interum print-outs * The team data is sorted by time at leg-end and the times printed are * real times at leg end. * This operation is designed to be quick - it doesn't update the disk file * and is not available in an HTML version - yet */ cur( 0, 5 ); printf( "Leg finishing time report\n" ); while( TRUE ) { d_field( 0, 7, "Enter leg to print :", D_NUMBER, 1, ( char * ) &leg, TRUE, M_UPDATE ); if( abort_flag ) return; if( leg <= config.num_legs ) break; beep(); } pri_leg_body ( leg ); } void pri_leg_body(int leg) { ty_s_data *ptr; int i, k; /* * Sort the data in finishing order */ printf( "\nSorting the data\n" ); flush_out(); if( ck_data( leg, C_END ) ) return; /* Check data for this leg */ sort_team_data( leg, S_FIN ); /* Sort the data */ /* * Now print the data on the printer */ if( !open_printer( "", tprintf("lg%1.1d", leg ), 80, report_html, leg ? tprintf ("Finish order for Leg %d.", leg) : "Final team finish order" ) ) { return; } /* * Print out the data */ print( "PRELIMINARY RESULTS ONLY\n\n" ); print_underline( TRUE ); print( "%4s %4s %-8s ", "Plce", "Team", "Time" ); print( "%4s %4s %-8s ", "Plce", "Team", "Time" ); print( "|" ); print( "%4s %4s %-8s ", "Team", "Plce", "Time" ); print( "%4s %4s %-8s\n", "Team", "Plce", "Time" ); print_underline( FALSE ); for( ptr = sort_data, k = 0, i = config.min_team; i <= config.max_team; ) { p_place( ptr++, leg, k++ ); p_place( ptr++, leg, k++ ); print( "|" ); while( i <= config.max_team && !valid_field( i ) ) i++; p_team( i++, leg ); while( i <= config.max_team && !valid_field( i ) ) i++; p_team( i++, leg ); print( "\n" ); } printf( "\n\n" ); print_underline( TRUE ); print( "%4s %4s %-8s ", "Plce", "Team", "Time" ); // print( "%4s %4s %-8s ", "Plce", "Team", "Time" ); print( "|" ); // print( "%4s %4s %-8s ", "Team", "Plce", "Time" ); print( "%4s %4s %-8s\n", "Team", "Plce", "Time" ); print_underline( FALSE ); for( ptr = sort_data, k = 0, i = config.min_team; i <= config.max_team; ) { p_place( ptr++, leg, k++ ); // p_place( ptr++, leg, k++ ); print( "|" ); while( i <= config.max_team && !valid_field( i ) ) i++; p_team( i++, leg ); // while( i <= config.max_team && !valid_field( i ) ) // i++; // p_team( i++, leg ); print( "\n" ); } /* * Insert the leg statistics */ gen_stats(); /* Generate all stats */ print( "\nLeg statistics\n" ); print( "Fastest team: %4d time : %s.", stats.fast.team[leg][0], time_a( stats.fast.time[leg][0] ) ); print( " Average time: %s\n", time_a( stats.average[leg][0] ) ); close_printer(); } /*======================================================================== * * Print place information * * Purpose: * This helper function is called to Print place information * in a 20-character field * * Parameters: * ptr Address of the place data * leg Leg to print * k Current index into sorted array. Simply * used to determine if the entry is valid * or if it should be space-filled * * Returns: * Nothing * *========================================================================*/ void p_place( ty_s_data * ptr, int leg, unsigned k ) { if( k < sort_num ) { print( "%4.4s %4d %8s ", pr_place( ptr->place, ptr->flags.bad_times ), ptr->team, time_fa( ptr->leg[leg], ptr->flags.disqualified ) ); } else { print( "%20s", "" ); } } /*======================================================================== * * Print team information * * Purpose: * This helper function is called to Print team information * in a 20-character field * * Parameters: * i team to print * leg Leg to print * * Returns: * Nothing * *========================================================================*/ void p_team( int i, int leg ) { ty_s_data *ptra; /* Pointer to sort data */ int found = FALSE; unsigned j; if( valid_field( i ) ) { ptra = sort_data; for( j = 1; j <= sort_num; j++, ptra++ ) if( i == ptra->team ) { found = TRUE; break; } } if( found ) { print( "%4d %4.4s %8s ", ptra->team, pr_place( ptra->place, ptra->flags.bad_times ), time_fa( ptra->leg[leg], ptra->flags.disqualified ) ); } else { print( "%20s", "" ); } } /*======================================================================== * * Print on elapsed times for given leg * * Purpose: * This function is called to Print on elapsed times for given leg * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_eleg(void) { int leg = 0; /* * This function is used to provide interum print-outs * The team data is sorted by time at leg-elapsed and the times printed are * real times at leg end. * This operation is designed to be quick - it doesn't update the disk file * and is not available in an HTML version - yet */ cur( 0, 5 ); printf( "Leg elapsed time report\n" ); while( TRUE ) { d_field( 0, 7, "Enter leg to print :", D_NUMBER, 1, ( char * ) &leg, TRUE, M_UPDATE ); if( abort_flag ) return; if( leg <= config.num_legs ) break; beep(); } pri_eleg_body(leg); } void pri_eleg_body( int leg) { ty_s_data *ptr; int i, k; /* * Sort the data in finishing order */ printf( "\nSorting the data\n" ); flush_out(); if( ck_data( leg, C_ELAPSED ) ) return; /* Check data for this leg */ sort_team_data( leg, S_L ); /* Sort the data on elapsed time */ /* * Now print the data on the printer */ if( !open_printer( "", tprintf( "le%1.1d", leg ), 80, report_html, leg ? tprintf( "Elapsed time order for Leg %d.", leg ) : tprintf( "Final elapsed team finishing order." ) ) ) { return; } /* * Print out the data */ print( "PRELIMINARY RESULTS ONLY\n\n" ); print_underline( TRUE ); print( "%4s %4s %-8s ", "Plce", "Team", "Time" ); print( "%4s %4s %-8s ", "Plce", "Team", "Time" ); print( "|" ); print( "%4s %4s %-8s ", "Team", "Plce", "Time" ); print( "%4s %4s %-8s\n", "Team", "Plce", "Time" ); print_underline( FALSE ); for( ptr = sort_data, k = 0, i = config.min_team; i <= config.max_team; ) { pe_place( ptr++, leg, k++ ); pe_place( ptr++, leg, k++ ); print( "|" ); while( i <= config.max_team && !valid_field( i ) ) i++; pe_team( i++, leg ); while( i <= config.max_team && !valid_field( i ) ) i++; pe_team( i++, leg ); print( "\n" ); } print( "\n\n" ); print_underline( TRUE ); print( "%4s %4s %-8s ", "Plce", "Team", "Time" ); // print( "%4s %4s %-8s ", "Plce", "Team", "Time" ); print( "|" ); // print( "%4s %4s %-8s ", "Team", "Plce", "Time" ); print( "%4s %4s %-8s\n", "Team", "Plce", "Time" ); print_underline( FALSE ); for( ptr = sort_data, k = 0, i = config.min_team; i <= config.max_team; ) { pe_place( ptr++, leg, k++ ); // pe_place( ptr++, leg, k++ ); print( "|" ); while( i <= config.max_team && !valid_field( i ) ) i++; pe_team( i++, leg ); // while( i <= config.max_team && !valid_field( i ) ) // i++; // pe_team( i++, leg ); print( "\n" ); } /* * Insert the leg statistics */ gen_stats(); /* Generate all stats */ print( "\nLeg statistics\n" ); print( "Fastest team: %4d time : %s.", stats.fast.team[leg][0], time_a( stats.fast.time[leg][0] ) ); print( " Average time: %s\n", time_a( stats.average[leg][0] ) ); close_printer(); } /*======================================================================== * * Print place information * * Purpose: * This helper function is called to Print place and elapsed information * in a 20-character field * * Parameters: * ptr Address of the place data * leg Leg to print * k Current index into sorted array. Simply * used to determine if the entry is valid * or if it should be space-filled * * Returns: * Nothing * *========================================================================*/ void pe_place( ty_s_data * ptr, int leg, unsigned k ) { if( k < sort_num ) { print( "%4.4s %4d %8s ", pr_place( ptr->place, ptr->flags.bad_times ), ptr->team, time_fa( ptr->lege[leg], ptr->flags.disqualified ) ); } else { print( "%20s", "" ); } } /*======================================================================== * * Print team information * * Purpose: * This helper function is called to Print team and elapsed time * information * in a 20-character field * * Parameters: * i Team to print * leg Leg to print * * Returns: * Nothing * *========================================================================*/ void pe_team( int i, int leg ) { ty_s_data *ptra; /* Pointer to sort data */ int found = FALSE; unsigned j; if( valid_field( i ) ) { ptra = sort_data; for( j = 1; j <= sort_num; j++, ptra++ ) if( i == ptra->team ) { found = TRUE; break; } } if( found ) { print( "%4d %4.4s %8s ", ptra->team, pr_place( ptra->place, ptra->flags.bad_times ), time_fa( ptra->lege[leg], ptra->flags.disqualified ) ); } else { print( "%20s", "" ); } } /*======================================================================== * * Print final results in HTML * * Purpose: * This function is called to Print final results with HTML formatting * All result files are created * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_final_html(void) { /* ** Generate ALL results with HTML tags */ report_html = html; pri_final(); report_html = printed; pri_final(); report_html = text; } /*======================================================================== * * Print final results * * Purpose: * This function is called to Print final results * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_final(void) { ty_s_data *ptr; unsigned i; int j, last_class; char suppress_classes; /* Boolean. Printout class files too */ char *report_title; bool class_done[MAX_CLASS+1]; int lcount; cur( 0, 5 ); printf( "Generate final result printouts\n" ); if( ck_data( -1, C_ELAPSED ) ) return; /* check data for all legs */ /* ** If a non HTML report then ask if the user want to supress the class ** printout. For an HTML report always do the class reports as the two ** are interlinked */ if ( ! report_html && ! report_all) { suppress_classes = getyes( "Do you want to suppress class printouts" ); } else { suppress_classes = FALSE; } /* ** Sort on every thing ** Then generate all the stats too */ printf( "\nSorting the data\n" ); do_big_sort(); gen_stats(); /* * Now print the data on the printer */ printf( "\nGenerating the printed output\n" ); if( !open_printer( "", "finish", 132, report_html, "Finishing Order" ) ) return; /* * Print out the data */ print_class_header( -1, TRUE ); /* Print the header */ ptr = sort_data; sort_team_data( 0, S_L ); /* Re-sort on elapsed time */ lcount = 0; for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { if ( ptr->class == config.nonequestrian_class ) continue; g_record( ptr->team, &team_buf ); /* ** If printing an HTML report then we need to mark ** the entry with a reference so that we can link to it */ if ( report_html == html ) { print( "",team_buf.numb ); } /* ** Print the basics (Finishing order) ** - Place within complete field ** - Team number - with HTML reference to team file ** - Class */ if ( report_html == printed && lcount %5 == 4 ) print_underline( TRUE ); print( "%4.4s ", pr_place( team_buf.leg[0].l_place, ptr->flags.bad_times ) ); if ( report_html == html ) print( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); if ( report_html == html ) print( "" ); print( " %-*s", 3, team_buf.class == 0 ? "" : config.team_class[team_buf.class - 1].abr ); /* ** Print the per-leg data ** - Time ** - Leg place ** - End place */ for( j = 1; j <= config.num_legs; j++ ) { /* ** Ensure that non-equestrian leg data is not displayed */ if ( j == config.equestrian_leg && team_buf.flags.non_equestrian ) { print( " %-8s %4.4s %4.4s", "-- NE --", "NE","NE"); } else { print( " %-8s %4.4s %4.4s", time_a( team_buf.leg[j].elapsed ), pr_place( team_buf.leg[j].l_place, ptr->flags.bad_times ), pr_place( team_buf.leg[j].le_place,ptr->flags.bad_times ) ); } } /* ** Print the trailer (Finishing order) ** - Total time ** - Category place - with reference to category file */ // print( " %-8s ", time_a( team_buf.leg[0].elapsed ) ); print( " %-8s ", time_a( ptr->lege[0] ) ); if ( report_html == html ) print( "",url_encode(p_filename(filebase, config.team_class[team_buf.class - 1].abr ,"html")), team_buf.numb ); print( "%-4.4s", pr_place_ne( team_buf.leg[0].lc_place, ptr->flags.bad_times, ptr->flags.non_equestrian ) ); if ( report_html == html ) print( "" ); if ( report_html == printed && lcount %5 == 4 ) print_underline( FALSE ); lcount++; print( "\n" ); } print_class_stats( -1, TRUE ); /* Print statistics */ print_legend(-1, 1 ); /* Print the legend */ close_printer(); /* Close the printer */ /* * Now produce a breakdown on a class by class basis * Now print out the class placement information */ if( suppress_classes ) { printf( "WARNING: Class printouts suppressed\n" ); return; } sort_team_data( 0, S_LC ); /* Generate class placement data */ last_class = -1; /* Invalid class to start with */ memset ( class_done, 0, sizeof(class_done)); for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { /* ** Detect a change in the "class" ** All data is within the one array of data ** Use the in-memory class as this MAY differ from that stored ** The non-equestrian class does this. */ if( last_class != ptr->class ) { if( last_class >= 0 ) { print_class_stats( last_class, TRUE ); print_legend( last_class, 1 ); close_printer(); } report_title = tprintf( "Category results for : %-*s", LEN_CLASS_NAME, ptr->class == 0 ? "" : config.team_class[ptr->class - 1].full_name ); if( !open_printer( "", config.team_class[ptr->class - 1].abr, 132, report_html, report_title ) ) continue; print_class_header( last_class = ptr->class, TRUE ); /* ** Mark the class as done */ class_done[ptr->class] = TRUE; lcount = 0; } /* ** Now read in the team record */ g_record( ptr->team, &team_buf ); /* ** If printing an HTML report then we need to mark ** the entry with a reference so that we can link to it */ if ( report_html == html ) print( "",team_buf.numb ); /* ** Print the basics ** - Place within the class ** - Team number - with HTML reference to team file ** - Class */ if ( report_html == printed && lcount %5 == 4 ) print_underline( TRUE ); print( "%4.4s ", pr_place( team_buf.leg[0].lc_place, ptr->flags.bad_times ) ); if ( report_html == html ) print( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); if ( report_html == html ) print( "" ); print( " %-*s", 3, team_buf.class == 0 ? "" : config.team_class[team_buf.class - 1].abr ); for( j = 1; j <= config.num_legs; j++ ) { /* ** Ensure that non-equestrian leg data is not displayed */ if ( j == config.equestrian_leg && (ptr->class == config.nonequestrian_class || ptr->flags.non_equestrian) ) { print( " %-8s %4.4s %4.4s", "-- NE --", "NE","NE"); } else { print( " %-8s %4.4s %4.4s", time_a( team_buf.leg[j].elapsed ), pr_place( team_buf.leg[j].lc_place, ptr->flags.bad_times ), pr_place( team_buf.leg[j].lec_place, ptr->flags.bad_times ) ); } } /* ** Print the trailer ** - Total time ** - Overall place - with reference to overall place file */ /* print( " %-8s ", time_a( team_buf.leg[0].elapsed ) ); */ print( " %-8s ", time_a( ptr->lege[0] ) ); if ( report_html == html ) print( "", url_encode(p_filename(filebase, "finish" ,"html")), team_buf.numb ); print( "%4.4s", pr_place( team_buf.leg[0].l_place, ptr->flags.bad_times || (ptr->class == config.nonequestrian_class))); if ( report_html == html ) print( "" ); if ( report_html == printed && lcount %5 == 4 ) print_underline( FALSE ); lcount++; print( "\n" ); } print_class_stats( last_class, TRUE ); print_legend(last_class,1); close_printer(); /* ** Pickup missed classes and create a report */ for( j = 1; j <= config.num_class; j++ ) { if ( class_done[j] ) { continue; } report_title = tprintf( "Category results for : %-*s", LEN_CLASS_NAME, config.team_class[j - 1].full_name ); if( !open_printer( "", config.team_class[j - 1].abr, 132, report_html, report_title ) ) continue; print_class_header( j-1, TRUE ); print( "\nThere were no competitors in this class\n" ); print_legend(j,1); close_printer(); } /* ** If we are generating an HTML report then we need to create the file ** that contains all the team names - the assumption is that this data ** is available */ if ( report_html ) { pri_team(); } /* ** Generate the awards report. ** This is only available as an HTML report */ if ( report_html ) { pri_awards_html(); } /* ** Generate the master index page */ if ( report_html ) { pri_master_index(); } pri_name_index_body(); } /*======================================================================== * * Place to text * * Purpose: * This function is called to convert a place to text * * Parameters: * place * * Returns: * text * *========================================================================*/ char *placing ( int place ) { if ( place > MAX_PLACE ) { return tprintf( "Place: %d", place); } return tprintf ("%s Place", place_text[place]); } /*======================================================================== * * Print award results * * Purpose: * This function is called to Print award results * Keep the page to 80 cols, so that it can be pronted on A4 * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_awards_html(void) { report_type saved = report_html; /* ** Generate ALL results with HTML tags */ report_html = html; pri_awards(); report_html = saved; } /*======================================================================== * * Print award results * * Purpose: * This function is called to Print award results * Keep the page to 80 cols, so that it can be pronted on A4 * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_awards(void) { int j; int i; int k; int windex; int winmax; ty_s_data *ptr; int last_class; char solid_line[100]; /* ** Calculate Summary information ** Should cache the data */ t_class_summary sdata; calc_class_summary( & sdata ); if( !open_printer( "", "awards", 80, report_html, "Prizes and Awards" ) ) return; memset ( solid_line, 0, sizeof( solid_line )); memset ( solid_line, '-', 80 ); /* ** Generate an index for this page */ print( "\n"); if ( report_html == html ) { print( "
" ); print( "",url_encode("INDEX")); } print( "Award Categories"); for( j = 1; j <= config.num_class; j++ ) { /* ** Header for the class */ if ( config.class_winners[j-1] <= 0 ) continue; winmax = config.class_winners[j-1]; { int valid = sdata.class[j].total - sdata.class[j].disqualified; // - sdata.class[j].non_equestrian; if ( valid < winmax ) winmax = valid; } print( "\n"); print( " "); if ( report_html == html ) print( "",url_encode(config.team_class[j-1].full_name)); print( "%s", tprintf( "%-*s", LEN_CLASS_NAME ,config.team_class[j-1].full_name )); if ( report_html == html ) print( "" ); print( " %3d Awards", winmax ); if ( config.class_winners[j-1] != winmax ) print( " from a maximum of %3d", config.class_winners[j-1] ); } /* ** Manual entries */ print( "\n"); print( " "); if ( report_html == html ) print( "",url_encode("Hall Of Fame")); print( "%s", "Hall Of Fame" ); if ( report_html == html ) print( "" ); print( "\n"); print( " "); if ( report_html == html ) print( "",url_encode("FASTEST")); print( "%s", "FASTEST" ); if ( report_html == html ) print( "" ); /* ** Sort the data by class */ sort_team_data( 0, S_LC ); /* Generate class placement data */ last_class = -1; /* Invalid class to start with */ /* ** Process each category */ print( "\n"); for( j = 1; ; j++ ) { /* ** Tail for previous entry */ if ( j != 1 ) if ( report_html == html ) print( "Awards Index",url_encode("INDEX")); if ( j > config.num_class ) break; /* ** Header for the class */ print( "\n"); if ( report_html == html ) { print( "
" ); print( "",url_encode(config.team_class[j-1].full_name)); } else { print( "%s\n", solid_line); } print( "Category: "); if ( report_html == html ) print( "",url_encode(p_filename(filebase, config.team_class[j - 1].abr ,"html"))); print( "%s", config.team_class[j-1].full_name ); if ( report_html == html ) print( "" ); if ( config.class_winners[j-1] <= 0 ) { print( "\n"); print( "No winners awarded" ); continue; } /* ** Enties for 'n' the best teams as configured */ windex = 0; /* Winners done */ for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { if ( ptr->class != j ) { continue; } /* ** Now read in the team record */ if( valid_field( ptr->team ) && g_record( ptr->team, &team_buf ) ) { /* ** Ensure we have a valid team ** Can't award disqualified teams ** Can't award NE teams unless its a NE award */ if ( ptr->flags.bad_times ) break; if ( ptr->class != config.nonequestrian_class && ptr->flags.non_equestrian ) break; /* ** Count the entry */ windex++; /* ** If printing an HTML report then we need to mark ** the entry with a reference so that we can link to it */ print( "\n"); if ( report_html == html ) { print( "",team_buf.numb ); print( "" ); } /* ** Basic information ** - Team number - with Xref back to full result ** - Full team name ** - Full categoray name */ print( "%s", placing(windex) ); print( " Team Name: "); if ( report_html == html ) print( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%-*s ", MAX_TM_NAME, team_buf.name ); if ( report_html == html ) print( "" ); print( " Number: "); if ( report_html == html ) print( "", url_encode(p_filename(filebase, "finish" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); if ( report_html == html ) print( "" ); for( k = 0; k < MAX_MEMB; k++ ) { /* ** Skip equestrian leg in the non-equestion display */ if ( k + 1 == config.equestrian_leg && ptr->class == config.nonequestrian_class) continue; print( "\n"); print( " "); print( "%-*s", MAX_PERSON_NAME, config.leg_name[k] ? config.leg_name[k] : "Competitor" ); print( " %-*s", MAX_PERSON_NAME, team_buf.members[k].name ); print( " %-8s", time_a( team_buf.leg[k+1].elapsed ) ); } print( "\n"); print( " "); print_bold( TRUE ); print( "%-*s %-*s %-8s", MAX_PERSON_NAME , "Total" ,MAX_PERSON_NAME, "",time_a( team_buf.leg[0].elapsed ) ); print_bold( FALSE ); print( "\n" ); } /* ** More to do */ if ( windex >= config.class_winners[j-1] ) { break; } } } /* ** Generate the Hall of Fame information */ print( "\n"); if ( report_html == html ) { print( "
" ); print( "",url_encode("Hall Of Fame")); } else { print( "%s\n", solid_line); } print( "%s", "Hall of Fame" ); if ( config.num_fame ) { for( i = 1; i <= config.num_fame; i++ ) { print( "\n"); print( " %-*s", MAX_PERSON_NAME, config.hall_fame[i-1] ); } } else { printf( "\n There are no new stars for the Hall of Fame"); } if ( report_html == html ) print( "\n"); if ( report_html == html ) print( "Awards Index",url_encode("INDEX")); /* ** Generate the FASTEST information */ print( "\n" ); print( "\n"); if ( report_html == html ) { print( "
" ); print( "",url_encode("FASTEST")); } else { print( "%s\n", solid_line); } print( "%s", "FASTEST" ); /* ** Sort the data and then generate the stats - again */ do_big_sort(); gen_stats(); for( i = 1; i <= config.num_legs; i++ ) { g_record( stats.fast.team[i][0], &team_buf ); print( "\n"); print( " %-13s ", config.leg_name[i - 1] ); print( " Name: "); if ( report_html == html ) print( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%-*s", MAX_PERSON_NAME, team_buf.members[i-1].name ); if ( report_html == html ) print( "" ); print( " Team :"); if ( report_html == html ) print( "", url_encode(p_filename(filebase, "finish" ,"html")), team_buf.numb ); print( "%4d" , stats.fast.team[i][0] ); if ( report_html == html ) print( " " ); print( "Time:%s ", time_a( stats.fast.time[i][0] ) ); } if ( report_html == html ) print( "\n"); if ( report_html == html ) print( "Awards Index",url_encode("INDEX")); print( "\n"); close_printer(); } /*======================================================================== * * pri_master_index * * Purpose: * This function is called to create an HTML page that references all * the other pages that have been generated * * Assume that they are in the same directory * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_master_index_entry(char *name, char *text) { print( ""); print ("%s\n", url_encode(p_filename(filebase, name ,"html")), text ); } void pri_master_index(void) { int j; report_html = html; if( !open_printer( "", "index", 132, report_html, "Master Index" ) ) return; /* ** Names */ print( "" ); pri_master_index_entry( "name", "Team list" ); pri_master_index_entry( "competitor", "Competitor list" ); pri_master_index_entry( "finish", "Finishing Order for all Teams" ); pri_master_index_entry( "awards", "Prizes and Awards" ); print( "
\n" ); print( "\n" ); for( j = 1; j <= config.num_class; j++ ) { pri_master_index_entry( config.team_class[j - 1].abr, tprintf("Category Results for: %s", config.team_class[j-1].full_name) ); } print( "
" ); close_printer(); /* ** A small page to hold the Leg End displays */ if( !open_printer( "", "legindex", 132, report_html, "Master Index with trace data" ) ) return; /* ** Names */ print( "" ); #if 1 pri_master_index_entry( "name", "Team list" ); pri_master_index_entry( "competitor", "Competitor list" ); pri_master_index_entry( "finish", "Finishing Order for all Teams" ); pri_master_index_entry( "awards", "Prizes and Awards" ); print( "
\n" ); print( "\n" ); for( j = 1; j <= config.num_class; j++ ) { pri_master_index_entry( config.team_class[j - 1].abr, tprintf("Category Results for: %s", config.team_class[j-1].full_name) ); } #endif print( "
\n" ); print( "\n" ); for ( leg = 1; leg <= config.num_legs; leg ++ ) { pri_master_index_entry( tprintf("lg%1.1d", leg), tprintf("Leg End Results for: %d", leg) ); } print( "
\n" ); print( "\n" ); for ( leg = 1; leg <= config.num_legs; leg ++ ) { pri_master_index_entry( tprintf("le%1.1d", leg), tprintf("Leg Elapsed Time Results for: %d", leg) ); } print( "
" ); close_printer(); } /*======================================================================== * * Print interim results * * Purpose: * This function is called to Print interim results * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_interim(void) { ty_s_data *ptr; unsigned i; int j, last_class; char suppress_classes = FALSE; /* Boolean. Printout class files too */ char *report_title; if ( ! report_all ) { cur( 0, 5 ); printf( "Generate interim result printouts\n" ); ck_data( -1, C_DISQUAL ); /* Check the data - dummy check */ suppress_classes = getyes( "Do you want to suppress class printouts" ); printf( "\nSorting the data\n" ); } do_big_sort(); /* Sort on every thing */ gen_stats(); /* Generate the stats too */ printf( "\nGenerating the printed output\n" ); /* * Now print the data on the printer */ if( !open_printer( "", "int", 132, report_html, "Interim Results" ) ) return; /* * Print out the data */ print_class_header( -1, FALSE ); /* Print the header */ ptr = sort_data; sort_team_data( 0, S_TEAM ); /* Re-sort on team number */ for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { if ( ptr->class == config.nonequestrian_class ) continue; g_record( ptr->team, &team_buf ); print( "%4d %4.4s %-*s", team_buf.numb, pi_place( team_buf.leg[config.num_legs].le_place, ptr->flags.disqualified, team_buf.leg[0].elapsed ), 3, team_buf.class == 0 ? "" : config.team_class[team_buf.class - 1].abr ); for( j = 1; j <= config.num_legs; j++ ) { print( " %-8s %4.4s %4.4s", time_fa( team_buf.leg[j].elapsed, ptr->flags.disqualified ), pi_place( team_buf.leg[j].l_place, ptr->flags.disqualified, team_buf.leg[j].elapsed ), pi_place( team_buf.leg[j].le_place, ptr->flags.disqualified, team_buf.leg[j].elapsed ) ); } print( " %-8s %4.4s\n", time_fa( team_buf.leg[0].elapsed, ptr->flags.disqualified ), pi_place( team_buf.leg[config.num_legs].lec_place, ptr->flags.disqualified, team_buf.leg[0].elapsed ) ); } print_class_stats( -1, FALSE ); /* Print statistics */ print_legend(-1, 1); /* Print the legend */ close_printer(); /* Close the printer */ /* * Now produce a breakdown on a class by class basis * Now print out the class placement information */ if( suppress_classes ) { printf( "WARNING: Class printouts suppressed\n" ); return; } sort_team_data( 0, S_CLASS ); /* Generate class placement data */ last_class = -1; /* Invalid class to start with */ for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { /* ** Detect a change in the "class" ** All data is within the one array of data ** Use the in-memory class as this MAY differ from that stored ** The non-equestrian class does this. */ if( last_class != ptr->class ) { if( last_class >= 0 ) { print_class_stats( last_class, TRUE ); print_legend(last_class, 1); close_printer(); } report_title = tprintf( "Interim Category results for : %-*s", LEN_CLASS_NAME, team_buf.class == 0 ? "" : config.team_class[ptr->class - 1].full_name ); if( !open_printer( "", tprintf( "i%2s", config.team_class[ptr->class - 1].abr ), 132, report_html, report_title ) ) continue; print_class_header( last_class = ptr->class, FALSE ); } /* ** Now read in the team record */ g_record( ptr->team, &team_buf ); print( "%4d %4.4s %-*s", team_buf.numb, pi_place( team_buf.leg[config.num_legs].lec_place, ptr->flags.disqualified, team_buf.leg[0].elapsed ), 3, team_buf.class == 0 ? "" : config.team_class[team_buf.class - 1].abr ); for( j = 1; j <= config.num_legs; j++ ) { print( " %-8s %4.4s %4.4s", time_fa( team_buf.leg[j].elapsed, ptr->flags.disqualified ), pi_place( team_buf.leg[j].lc_place, ptr->flags.disqualified, team_buf.leg[j].elapsed ), pi_place( team_buf.leg[j].lec_place, ptr->flags.disqualified, team_buf.leg[j].elapsed ) ); } print( " %-8s %4.4s\n", time_fa( team_buf.leg[0].elapsed, ptr->flags.disqualified ), pi_place( team_buf.leg[config.num_legs].le_place, ptr->flags.disqualified, team_buf.leg[0].elapsed ) ); } print_class_stats( last_class, FALSE ); print_legend(last_class, 1); close_printer(); } /*---------------------------------------------------------------------------- ** FUNCTION : pri_csv_data ** ** DESCRIPTION : Generate a CSV file of all the report data ** It can then be used to play with the data externally ** ** ** INPUTS : None ** ** RETURNS : Yes it does ** ----------------------------------------------------------------------------*/ void pri_csv_data ( void ) { int i; int j; int age_sum; /* ** Sort on every thing ** Then generate all the stats too */ printf( "\nSorting the data\n" ); do_big_sort(); gen_stats(); /* * Now print the data on the printer */ if( !open_printer( "full_data", "csv", 2000, FALSE, NULL ) ) return; printf( "\nGenerating the printed output\n" ); /* ** Print headings */ csv_print( "%s", "Team Number" ); csv_print( "%s", "Team Name" ); csv_print( "%s", "Class Full"); csv_print( "%s", "Class Abr"); csv_print( "%s", "Class Start Time"); csv_print( "%s", "Class Start Time Number"); csv_print( "%s", "Team Country"); for( j = 1; j <= config.num_legs; j++ ) { csv_print( "%s", "Leg Number" ); csv_print( "%s", "Leg Name"); csv_print( "%s", "Competitor Name"); csv_print( "%s", "Sex" ); csv_print( "%s", "Age"); csv_print( "%s", "Start Time"); csv_print( "%s", "Start Time Number"); csv_print( "%s", "End Time" ); csv_print( "%s", "End Time Number" ); csv_print( "%s", "Elapsed Time"); csv_print( "%s", "Elapsed Time Number"); csv_print( "%s", "Leg Place"); csv_print( "%s", "Leg End Place"); csv_print( "%s", "Leg Class Place"); csv_print( "%s", "Leg End Class Place"); csv_print( "%s", "Manual"); } j = 0; csv_print( "%s", "Team Start Time"); csv_print( "%s", "Team Start Time Number"); csv_print( "%s", "Team End Time"); csv_print( "%s", "Team End Time Number"); csv_print( "%s", "Team Elapsed Time"); csv_print( "%s", "Team Elapsed Time Number"); // csv_print( "%s", team_buf.leg[j].l_place ); csv_print( "%s", "Team Leg End Place"); // csv_print( "%s", team_buf.leg[j].lc_place ); csv_print( "%s", "Team Leg Class Place"); // csv_print( "%s", team_buf.leg[j].manual ); csv_print( "%s", "Total Team Age"); csv_print( "%s", "Flag:valid Team"); csv_print( "%s", "Flag:bad_times" ); csv_print( "%s", "Flag:disqualified" ); csv_print( "%s", "Flag:non_equestrian" ); csv_print("\n"); for( i = config.min_team; i <= config.max_team; i++ ) { if( valid_field( i ) && g_record( i, &team_buf ) ) { /* ** Basic information ** - Team number - with Xref back to full result ** - Full team name ** - Full categoray name - with Xref to category results ** - Country name */ csv_print( "%d", team_buf.numb ); csv_print( "%s", team_buf.name ); csv_print( "%s", team_buf.class == 0 ? "" : config.team_class[team_buf.class - 1].full_name ); csv_print( "%s", team_buf.class == 0 ? "" : config.team_class[team_buf.class - 1].abr ); csv_print( "%s", time_a (team_buf.class == 0 ? 0 : config.team_class[team_buf.class - 1].start )); csv_print( "%d", team_buf.class == 0 ? 0 : config.team_class[team_buf.class - 1].start ); csv_print( "%s", config.num_countries == 0 || team_buf.country == 0 ? "" : config.country_name[team_buf.country - 1].full_name ); age_sum = 0; for( j = 1; j <= config.num_legs; j++ ) { csv_print( "%d", j ); csv_print( "%s", config.leg_name[j - 1] ); csv_print( "%s", team_buf.members[j-1].name ); csv_print( "%s", ( team_buf.members[j-1].sex == male ) ? "Male" : "Female" ); csv_print( "%d", team_buf.members[j-1].age ); if ( age_sum >= 0 ) { ushort age = team_buf.members[j-1].age; if ( age > 0 && age < 255 ) { age_sum += age; } else { age_sum = -1; } } csv_print( "%s", time_a(team_buf.leg[j].start )); csv_print( "%d", team_buf.leg[j].start ); csv_print( "%s", time_a(team_buf.leg[j].end )); csv_print( "%d", team_buf.leg[j].end ); csv_print( "%s", time_a(team_buf.leg[j].elapsed )); csv_print( "%d", team_buf.leg[j].elapsed ); csv_print( "%d", team_buf.leg[j].l_place ); csv_print( "%d", team_buf.leg[j].le_place ); csv_print( "%d", team_buf.leg[j].lc_place ); csv_print( "%d", team_buf.leg[j].lec_place ); csv_print( "%d", team_buf.leg[j].manual ); } j = 0; csv_print( "%s", time_a(team_buf.leg[j].start )); csv_print( "%d", team_buf.leg[j].start ); csv_print( "%s", time_a(team_buf.leg[j].end )); csv_print( "%d", team_buf.leg[j].end ); csv_print( "%s", time_a(team_buf.leg[j].elapsed )); csv_print( "%d", team_buf.leg[j].elapsed ); // csv_print( "%d", team_buf.leg[j].l_place ); csv_print( "%d", team_buf.leg[j].le_place ); // csv_print( "%d", team_buf.leg[j].lc_place ); csv_print( "%d", team_buf.leg[j].lec_place ); // csv_print( "%d", team_buf.leg[j].manual ); csv_print( "%d", age_sum ); csv_print( "%d", team_buf.flags.valid ); csv_print( "%d", team_buf.flags.bad_times ); csv_print( "%d", team_buf.flags.disqualified ); csv_print( "%d", team_buf.flags.non_equestrian ); //How about class placings csv_print( "\n" ); } } close_printer(); } /*======================================================================== * * Print all reports at once * Its all so fast, these days ... * * Purpose: * This function is called to print all reports at once * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_all_reports ( void ) { int leg; report_all = TRUE; pri_team(); for ( leg = 1; leg <= config.num_legs; leg ++ ) { pri_leg_body ( leg ); pri_eleg_body ( leg ); report_html = html; pri_leg_body ( leg ); pri_eleg_body ( leg ); report_html = text; } pri_final(); pri_final_html(); pri_csv_data(); pri_summary(); pri_awards_html(); pri_awards(); pri_master_index(); report_all = FALSE; } /*======================================================================== * * Print a class header * * Purpose: * This function is called to print a class header * * Parameters: * class Name of this class * final False - prelim results * * Returns: * Nothing * *========================================================================*/ void print_class_header( int class, int final ) { int j; /* ** Give a clear indication that the report is preliminary */ if( !final ) print( "PRELIMINARY RESULTS ONLY\n\n" ); /* ** Now printout the column headings ** This is a two line display ** ** Line-1 Leg names */ print( "%-*s %-*s %-*s", 4, "", 4, "", 3, "" ); for( j = 1; j <= config.num_legs; j++ ) { print_bold( TRUE ); print( " %-*s", 18, config.leg_name[j - 1] ); print_bold( FALSE ); } print( " %-8s %-4s\n", "Total", ( class < 0 ) ? "Cat" : "Fin" ); /* ** Line-2 Details */ print_underline( TRUE ); print( "%-*s %*s %-*s", 4, final ? "Plce" : "Team", 4, final ? "Team" : "Plce", 3, "Cat" ); for( j = 1; j <= config.num_legs; j++ ) print( " %-8s %-4s %-4s", "Time", " LP", " EP" ); print( " %-8s %-4s\n", "Time", "Plce" ); print_underline( FALSE ); } /*======================================================================== * * Generate the class stats * * Purpose: * This function is called to Generate the class stats * * Parameters: * c Class to print * final TRUE: Final data * FALSE: Interim data * * Returns: * Nothing * *========================================================================*/ void print_class_stats( int c, int final ) { int i, j; char *title; if( c < 0 ) { title = "Event"; c = 0; } else { title = "Category"; } print( "\n" ); if ( report_html ) print_underline(TRUE); print( "%s statistics", title ); if ( report_html ) print_underline(FALSE); print( "\n" ); /* ** Print the names of the different legs */ print( "%-*s ", LEN_CLASS_NAME, "" ); for( i = 1; i <= config.num_legs; i++ ) { print_bold( TRUE ); print( "%-13s ", config.leg_name[i - 1] ); print_bold( FALSE ); } print( "%-13s \n", final ? "Total" : "" ); /* ** Print the fastest teams for each leg and overall ** Add cross references to the team names for the fastest teams */ print( "%*s : ", LEN_CLASS_NAME, "Fastest" ); for( i = 0; i <= config.num_legs; i++ ) { j = i + 1; if( i >= config.num_legs ) { if( final ) j = 0; /* Leg-0 last */ else break; } if ( report_html == html ) print( "", url_encode(p_filename(filebase, "name" ,"html")), stats.fast.team[j][c] ); print( "%4d", stats.fast.team[j][c] ); if ( report_html == html ) print( "" ); print( " %s ", time_a( stats.fast.time[j][c] ) ); } print( "\n" ); /* ** Print the average time for each leg */ print( "%*s : ", LEN_CLASS_NAME, "Average" ); for( i = 0; i <= config.num_legs; i++ ) { j = i + 1; if( i >= config.num_legs ) { if( final ) j = 0; /* Leg-0 last */ else break; } print( " %s ", time_a( stats.average[j][c] ) ); } } /*======================================================================== * * Print the legend * * Purpose: * This function is called to Print the legend * * Parameters: * class - Class currently being printed * full - Display full legend * * Returns: * Nothing * *========================================================================*/ void print_legend ( int class, int full ) { int i; char line[201]; FILE *adfile = NULL; int count; /* * First the categories */ print( "\n\n" ); if ( report_html ) print_underline(TRUE); print( "Category abbreviations" ); if ( report_html ) print_underline(FALSE); print( "\n" ); for( i = 1, count = 0; i <= config.num_class; i++ ) { #if 0 /* ** Skip any non-equestrian class in the legend ** Don't want to tell the general user whats goes on, unless we actually ** creating the non-equestrian report. */ if ( class != config.nonequestrian_class && i == config.nonequestrian_class ) continue; #endif if ( report_html == html ) print( "",url_encode(p_filename(filebase, config.team_class[i - 1].abr ,"html")) ); print( "%-*s", 3, config.team_class[i - 1].abr ); if ( report_html == html ) print( "" ); print( " : %-*s ", LEN_CLASS_NAME, config.team_class[i - 1].full_name ); if( !( ++count % 5 ) ) print( "\n" ); } /* ** Add link to the finish order report */ if ( report_html == html ) { print( "", url_encode(p_filename(filebase, "finish" ,"html")) ); print( "%-*s", 3, "All" ); print( "" ); print( " : %-*s ", LEN_CLASS_NAME, "Finishing Order" ); } /* ** Country data - if countries have been defined */ if( config.num_countries ) { print( "\n\n" ); if ( report_html ) print_underline(TRUE); print( "Country abbreviations" ); if ( report_html ) print_underline(FALSE); print( "\n" ); for( i = 0, count = 0; i < MAX_COUNTRY; i++ ) { if( config.country_name[i].abr[0] ) { print( "%-*s : %-*s ", 4, config.country_name[i].abr, LEN_CNTRY_NAME, config.country_name[i].full_name ); if( !( ++count % 5 ) ) print( "\n" ); } } } print( "\n" ); /* * Other comments */ if ( full ) { print( "\nPlace numbers (LP and EP)\n" ); print( "LP - Placing based on elapsed time within the leg. Cat Plce - Placing within the category.\n" ); print( "EP - Placing based on accumulated times to the end of that leg. Fin Plce - Overall placing within the event.\n" ); print( "U - Placing not available.\n" ); } /* * Insert the contents of the config.addendum file * or a defualt message */ if( config.addendum[0] ) adfile = fopen( config.addendum, "rt" ); /* Open the file for reading */ if( adfile ) { while( fgets( line, sizeof(line)-1, adfile ) ) print( "%s", line ); } else { print( "\nTiming and Results by\n" ); print( "Embedded Solutions\n" ); } } /*======================================================================== * * Return place data * * Purpose: * This function is called to return place data * * This routine is called to fill a print team_buffer - to allow for * multiple calls to this function ( before the data is used ) a number * of static team_buffers are maintained * * Parameters: * num place - if not bad_times * disq Disqualified flag * time Time data is based on * * Returns: * This function returns a pointer to the character string for the * number or a pointer to a bad_times string. * *========================================================================*/ char *pi_place( int num, int disq, time_t time ) { static char store[2][5]; /* 2 stores for 4 digit numbers */ static int i = 0; /* Current index into store */ static char *dis = "D"; /* Disqualified */ static char *non = "-"; /* Invalid time */ if( disq ) /* Disqualified team */ return ( dis ); if( time <= 0 ) /* Unknown time */ return ( non ); i++; if( i >= 2 ) i = 0; /* Select next entry */ sprintf( store[i], "%4d", num ); return ( store[i] ); } /*======================================================================== * * Return place data * * Purpose: * This function is called to Return place data * * This routine is called to fill a print team_buffer - to allow for * multiple calls to this function ( before the data is used ) a number * of static team_buffers are maintained * * Parameters: * num place - if not bad_times * disq Disqualified flag * * Returns: * This function returns a pointer to the character string for the * number or a pointer to a bad_times string. * *========================================================================*/ char *pr_place( int num, int disq ) { static char store[2][5]; /* 2 stores for 4 digit numbers */ static int i = 0; /* Current index into store */ static char *dis = "U"; if( disq ) return ( dis ); i++; if( i >= 2 ) i = 0; /* Select next entry */ sprintf( store[i], "%4d", num ); return ( store[i] ); } /*======================================================================== * * Return place data * * Purpose: * This function is called to Return place data * * This routine is called to fill a print team_buffer - to allow for * multiple calls to this function ( before the data is used ) a number * of static team_buffers are maintained * * Parameters: * num place - if not bad_times * disq Disqualified flag * ne Non Equestrian Flag * * Returns: * This function returns a pointer to the character string for the * number or a pointer to a bad_times string. * *========================================================================*/ char *pr_place_ne( int num, int disq, int ne ) { static char store[2][5]; /* 2 stores for 4 digit numbers */ static int i = 0; /* Current index into store */ static char *dis = "U"; if( disq && ! ne ) return ( dis ); if( ++i >= 2 ) i = 0; /* Select next entry */ sprintf( store[i], "%4d", num ); return ( store[i] ); } /*======================================================================== * * Check data for bad times * * Purpose: * This function is called to Check data for bad times * Scan the sort data structure and locate entries that have incorrect * times. * * Entries that have invalid leg times are displayed to the operator * and the report process can be aborted * * Parameters: * leg Leg to test * mode Either end or elapsed times to be tested * * Returns: * Returns FALSE if the report operation is to be aborted * *========================================================================*/ bool ck_data( int leg, int mode ) { ty_s_data *ptr; unsigned i; int bad = 0; int j = 0; int k, bad_leg; time_t *t; /* An array of times */ ptr = sort_data; for( i = 1; i <= sort_num; i++, ptr++ ) { bad_leg = 0; if( mode == C_DISQUAL ) { ptr->flags.bad_times = ptr->flags.disqualified; continue; } if( mode == C_ELAPSED ) t = ptr->lege; else t = ptr->leg; if ( leg >= 0 ) { ptr->flags.bad_times = (ptr->flags.disqualified && ! ptr->flags.non_equestrian); } else { ptr->flags.bad_times = ptr->flags.disqualified; } if( ! ptr->flags.bad_times ) { if( leg <= 0 ) { for( k = 0; k <= config.num_legs; k++ ) { if ( !(config.equestrian_leg && ptr->flags.non_equestrian && config.equestrian_leg == k )) bad_leg |= ( t[k] <= 0 ); } } else { bad_leg = t[leg] <= 0; } if( bad_leg ) { ptr->flags.bad_times = TRUE; if ( ! report_all ) { if( !bad ) printf( "Team with incorrect time information\n" ); if( ++j > 15 ) { printf( "\n" ); j = 0; } printf( "%4d ", ptr->team ); bad++; } } } } if( bad ) { printf( "\n%d teams with incorrect times.\n", bad ); return ( !getyes ( "These have been flagged as unplaced - continue report" ) ); } return ( FALSE ); } /*======================================================================== * * Update placing information * * Purpose: * This function is called to Update placing information * * This routine will rip through the data generating the team placing in * a) Within a leg * b) At the end of a leg * c) Within a leg by class * d) At the end of a leg by class * * This function is provided to allow the display routines to * be accessed and updated without the need to run a report * * Parameters: * xxxx a ptr to the xxxx stuff * * Returns: * Nothing * *========================================================================*/ void srt_place(void) { int i, j; cur( 0, 5 ); printf( "Update the team placings to the data base\n" ); flush_out(); if( ck_data( -1, C_ELAPSED ) ) return; do_big_sort(); /* * Generate the stats and display them on the screen for interest * This operation will not hurt - so why not */ gen_stats(); printf( "\nEvent statistics\n\n" ); printf( "%-*s %-13s ", LEN_CLASS_NAME, "", "Overall" ); for( i = 1; i <= config.num_legs; i++ ) printf( "%-13s ", config.leg_name[i - 1] ); for( j = 0; j <= config.num_class; j++ ) { printf( "\n%-*s : ", LEN_CLASS_NAME, j ? config.team_class[j - 1].full_name : "Overall" ); for( i = 0; i <= config.num_legs; i++ ) { printf( "%4d ", stats.fast.team[i][j] ); printf( "%s ", time_a( stats.fast.time[i][j] ) ); } printf( "\n%*s : ", LEN_CLASS_NAME, "Average" ); for( i = 0; i <= config.num_legs; i++ ) { printf( " %s ", time_a( stats.average[i][j] ) ); } } printf( "\nAny key to continue" ); ( void ) getinp(); } /*======================================================================== * * Calculate summary information * * Purpose: * This function is called to calculate summary information * * Parameters: * ptr - Address of a summary structure to fill in * * Returns: * Nothing * *========================================================================*/ void calc_class_summary( t_class_summary * ptr ) { int i; /* ** Reset the data */ memset ( ptr, 0, sizeof (*ptr )); /* * Extract the required data from the data base * Only save that information required for the operation */ for( i = config.min_team; i <= config.max_team; i++ ) { if( valid_field( i ) && g_record( i, &team_buf ) ) { ptr->total.total++; ptr->class[team_buf.class].total++; if ( team_buf.flags.disqualified ) { ptr->class[team_buf.class].disqualified++; ptr->total.disqualified++; } if ( config.nonequestrian_class && team_buf.flags.non_equestrian ) { ptr->class[team_buf.class].non_equestrian++; ptr->total.non_equestrian++; } } } /* ** Fix up the totals for the non equestrians ** This is not a real category but a summary of the others. */ if ( config.nonequestrian_class ) { ptr->class[config.nonequestrian_class].total += ptr->total.non_equestrian; } } /*======================================================================== * * Display summary information * * Purpose: * This function is called to display summary information * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void display_summary (void) { t_class_summary data; int i; int line = 2; cur( 0, line ); printf( "Generating Summary Information" ); calc_class_summary( & data ); /* ** Display summary stats */ cur( 0, line ); console_clreol(); printf( "Summary Information\n\n" ); printf( "%*s : %-7s %-7s%-7s\n", LEN_CLASS_NAME, "Category", "Total", "Disq", "NonEq" ); for( i = 0; i < config.num_class; i++ ) { /* ** The non-equestrian leg does not have any data ** Supress the display */ if ( config.nonequestrian_class == i+1 ) continue; printf( "%*s : %-7d %-7d %-7d\n", LEN_CLASS_NAME, config.team_class[i].full_name, data.class[i+1].total, data.class[i+1].disqualified, data.class[i+1].non_equestrian ); } printf( "\n" ); printf( "%*s : %-7d %-7d %-7d\n", LEN_CLASS_NAME, "Totals", data.total.total, data.total.disqualified, data.total.non_equestrian ); printf( "\nAny key to continue " ); getinp(); } /*======================================================================== * * Print summary information * * Purpose: * This function is called to print summary information * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_summary (void) { t_class_summary data; int i; int line = 2; if( !open_printer( "", "summary", 132, 0, "Summary Information" ) ) return; cur( 0, line ); printf( "Generating Summary Information" ); calc_class_summary( & data ); /* ** Display summary stats */ print( "%*s : %-7s %-7s%-7s\n", LEN_CLASS_NAME, "Category", "Total", "Disq", "NonEq" ); for( i = 0; i < config.num_class; i++ ) { /* ** The non-equestrian leg does not have any data ** Supress the display */ if ( config.nonequestrian_class == i+1 ) continue; print( "%*s : %-7d %-7d %-7d\n", LEN_CLASS_NAME, config.team_class[i].full_name, data.class[i+1].total, data.class[i+1].disqualified, data.class[i+1].non_equestrian ); } print( "\n" ); print( "%*s : %-7d %-7d %-7d\n", LEN_CLASS_NAME, "Totals", data.total.total, data.total.disqualified, data.total.non_equestrian ); close_printer(); if ( !report_all ) { printf( "\nAny key to continue " ); getinp(); } } /*======================================================================== * * Main sort routine for final data * * Purpose: * This function is called to do the report sort routine for final data * This routine will fill all the gaps in the sort_aux structure * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void do_big_sort(void) { int i, k; /* Looooopy things */ unsigned j; ty_s_data *ptr; /* Pointer to sort data */ int class; /* Current class */ printf( "Sorting it ALL out" ); flush_out(); for( i = 0; i <= config.num_legs; i++ ) { /* ** Sort on leg elapsed time ** Then save the teams elapsed place in each leg */ sort_team_data( i, S_L ); for( j = 1, k = 1, ptr = sort_data; j <= sort_num; ptr++, j++ ) { if ( ptr->class == config.nonequestrian_class ) continue; sort_aux[ptr->team].l_place[i] = k++; sort_aux[ptr->team].team = ptr->team; } /* ** Sort on leg end time ** Then save the teams place at the end of each leg */ sort_team_data( i, S_LE ); for( j = 1, k = 1, ptr = sort_data; j <= sort_num; ptr++, j++ ) { if ( ptr->class == config.nonequestrian_class ) continue; sort_aux[ptr->team].le_place[i] = k++; } /* ** Sort on elapsed time per class ** The save the teams elapsed place in each leg per class */ sort_team_data( i, S_LC ); class = -1; for( k = 1, j = 1, ptr = sort_data; j <= sort_num; j++, ptr++ ) { if( class != ptr->class ) { k = 1; class = ptr->class; } sort_aux[ptr->team].lc_place[i] = k++; } /* ** Sort on end time per class ** Then save the teams place at the end of each leg per class */ sort_team_data( i, S_LEC ); class = -1; for( k = 1, j = 1, ptr = sort_data; j <= sort_num; j++, ptr++ ) { if( class != ptr->class ) { k = 1; class = ptr->class; } sort_aux[ptr->team].lec_place[i] = k++; } } /* ** Write the place information back to disk for use in the displays */ printf( "\nWriting it all back to the disk file" ); flush_out(); for( i = config.min_team; i <= config.max_team; i++ ) { if( sort_aux[i].team && valid_field( i ) && g_record( i, &team_buf ) ) { for( k = 0; k <= config.num_legs; k++ ) { team_buf.leg[k].l_place = sort_aux[i].l_place[k]; team_buf.leg[k].le_place = sort_aux[i].le_place[k]; team_buf.leg[k].lc_place = sort_aux[i].lc_place[k]; team_buf.leg[k].lec_place = sort_aux[i].lec_place[k]; } put_team_record( i, &team_buf ); } } } /*======================================================================== * * Sort in memory buffer * * Purpose: * This function is called to Sort in memory buffer * * Parameters: * leg Requested leg * mode Defines the sort mode * * Returns: * Nothing * *========================================================================*/ void sort_team_data( int leg, int mode ) { unsigned j; ty_s_data *ptr; sort_leg = leg; /* Leg is global for the comparison function */ sort_mode = mode; /* Mode is global for compare function */ qsort( ( char * ) sort_data, sort_num, sizeof( ty_s_data ), sort_comp ); /* * Insert "place data" into the sorted data * This simply the index into the array of data - after its been * sorted. */ ptr = sort_data; for( j = 1; j <= sort_num; j++, ptr++ ) ptr->place = j; } /*======================================================================== * * qsort comparison function * * Purpose: * This function is called by qsort as a Sort comparison function * * Parameters: * a - 1st record * b - 2nd record * * Returns: * value to qsort * *========================================================================*/ int sort_comp( const void * aa, const void * bb ) { const ty_s_data * a = aa; const ty_s_data * b = bb; int i; /* One of those */ time_t ta, tb; /* Leg times */ int na, nb; /* Number of valid legs */ time_t tta, ttb; /* Temp times */ /* ** Sorting on Team Number */ if( sort_mode == S_TEAM ) return ( a->team - b->team ); /* ** Sorting on Class and Team Number */ if( sort_mode == S_CLASS ) { if( a->class != b->class ) return ( a->class - b->class ); else return ( a->team - b->team ); } /* ** Sorting within a class ** First sort on the class */ if( sort_mode == S_LEC || sort_mode == S_LC ) /* Sort within a class */ if( a->class != b->class ) return ( a->class - b->class ); #if 1 /* ** Always put the nonequestrian_class at the end ** Simplifies the creation of ordered lists as these ** Entries are not present in the main body */ if ( a->class == config.nonequestrian_class || b->class == config.nonequestrian_class ) { if ( a->class == config.nonequestrian_class && b->class == config.nonequestrian_class ) { } else { return ( a->class == config.nonequestrian_class ? 1 : -1 ); } } #endif /* ** Now we need to examine the times as we have sorted ** on every thing else. ** ** If one of the teams has bad_times, then that team is placed ** lower in the sorting order. If both teams have bad times ** then sort on team number. ie: Unplaced teams are sorted on ** team number ** ** If not sorting within a class (ie Overall), then Non_Equestrian ** is better than a bad time. Places NE before disqualified ** ** ** Note: NE also have bad_times set */ #if 1 if( a->flags.bad_times || b->flags.bad_times ) /* Valid data has precedence */ { if( a->flags.bad_times && b->flags.bad_times ) { if( a->flags.non_equestrian || b->flags.non_equestrian ) { if( a->flags.non_equestrian && b->flags.non_equestrian ) { /* ** Both are non equestrian ** Let the time sort operate ... */ //return ( a->team - b->team ); } else { /* One is equestrian */ /* Good times better than NE */ return ( a->flags.non_equestrian ? -1 : 1 ); } } else { /* Neither is equestrian */ return ( a->team - b->team ); } } else return ( a->flags.bad_times ? 1 : -1 ); } #else if( a->flags.bad_times || b->flags.bad_times ) /* Valid data has precedence */ { if( a->flags.bad_times && b->flags.bad_times ) return ( a->team - b->team ); else return ( a->flags.bad_times ? 1 : -1 ); } /* ** Not sorting within a class ie: Overall ** Non-Equestrian is at the end, so that it doesn't get counted in the ** finishing order */ if( sort_mode == S_LE || sort_mode == S_L ) /* Sort NOT within a class */ { if( a->flags.non_equestrian || b->flags.non_equestrian ) { if( a->flags.non_equestrian && b->flags.non_equestrian ) return ( a->team - b->team ); else return ( a->flags.non_equestrian ? 1 : -1 ); } } #endif /* ** Before we sort on times we must determine which time to ** use. Finish time, Leg end times, Leg Elapsed times. */ switch ( sort_mode ) { /* ** Sort on finish times */ case S_FIN: ta = a->leg[sort_leg]; tb = b->leg[sort_leg]; break; /* ** Sort on accumulated leg times */ case S_LE: case S_LEC: if( sort_leg ) { /* ** Calculate accumulated time up to the desired leg ** If the two teams have a different number of valid ** leg times then order by the team that has completed ** more legs. */ ta = tb = ( time_t ) 0; na = nb = 0; for( i = 1; i <= sort_leg; i++ ) { tta = a->lege[i]; ttb = b->lege[i]; if( tta > 0 ) { na++; ta += tta; } if( ttb > 0 ) { nb++; tb += ttb; } } if( na != nb ) return ( nb - na ); } else { ta = a->leg[sort_leg] - a->start; tb = b->leg[sort_leg] - b->start; } break; /* ** Sort on Elapsed times */ case S_LC: case S_L: ta = a->lege[sort_leg]; tb = b->lege[sort_leg]; break; /* ** Just to be sure ... */ default: return ( 0 ); } /* ** Finally. Compare the required team times */ if( ta == tb ) return ( a->team - b->team ); if( ( ta > 0 ) && ( tb > 0 ) ) return ( ( int ) ( ta - tb ) ); return ( ( ta > 0 ) ? -1 : 1 ); } /*======================================================================== * * qsort comparison function - competitor names * * Purpose: * This function is called by qsort as a Sort comparison function * * Parameters: * a - 1st record * b - 2nd record * * Returns: * value to qsort * *========================================================================*/ int sort_comp_cname( const void * aa, const void * bb ) { ty_s_namedata * a = (ty_s_namedata *)aa; ty_s_namedata * b = (ty_s_namedata *)bb; int i; /* One of those */ /* ** Sort by name */ i = strcmp ( a->name, b->name ); if ( i ) return ( i ); a->multi=1; b->multi=1; /* ** Sort by Leg */ i = a->leg - b->leg; if ( i ) return ( i ); /* ** Sorting on Team Number */ return ( a->team - b->team ); } /*======================================================================== * * load report data into memory * * Purpose: * This routine will pull all the data into memory * Not all the team data is loaded. Only that essential for the * operation of the sort routine is loaded * * Parameters: * None * * Returns: * TRUE - All is well * *========================================================================*/ bool load_report_data(void) { ty_s_data *ptr; /* pointer to sort data type */ ty_s_data *last; int j; unsigned num; printf( "Loading team information - This will not hurt" ); flush_out(); /* * Fetch memory for the data store */ if( sort_data ) free( ( char * ) sort_data ); sort_data = 0; if( sort_aux ) free( ( char * ) sort_aux ); sort_aux = 0; sort_num = 0; /* Counter of records in the array */ /* ** Allocate memory for the data structures ** This will be free'd */ num = config.max_team - config.min_team + 1 ; /* ** Allow for non-equestrian teams - since some of the data is loaded twice ** Take a guess that at most 1/2 the teams will be non-equestrian */ num = num * 3 / 2; sort_data = ( ty_s_data * ) calloc ( num , sizeof( ty_s_data ) ); sort_aux = ( ty_s_aux * ) calloc( num + 1, sizeof( ty_s_aux ) ); if( sort_data == 0 || sort_aux == 0 ) { printf( "\n\nError in allocating memory\n" ); sleep( 5 ); return ( FALSE ); } /* ** Load data into the memory based data structure ** Only load data for valid-teams ** Load essential data ** Team Number, class and flags ** Leg end and elapsed times */ ptr = sort_data; for( team = config.min_team; team <= config.max_team; team++ ) { if( valid_field( team ) ) { g_record( team, &team_buf ); if( team_buf.flags.valid ) { last = ptr; ptr->team = team; for( j = 0; j < MAX_LEGS + 1; j++ ) { ptr->lege[j] = team_buf.leg[j].elapsed; ptr->leg[j] = team_buf.leg[j].end; } ptr->start = team_buf.leg[0].start; ptr->class = team_buf.class; ptr->flags = team_buf.flags; ptr++; sort_num++; /* ** If non-equestrian support is enabled then ** duplicate and modify data for the non-equestrian teams ** - Change the class ** - Modify the leg time */ #if 1 if ( config.nonequestrian_class && team_buf.flags.non_equestrian ) { ptr->team = team; ptr->lege[0] = 0; for( j = 0; j < MAX_LEGS + 1; j++ ) { if ( j == config.equestrian_leg ) { last->lege[j] = ptr->lege[j] = 0; if ( config.equestrian_leg > 1 ) last->leg[j] = ptr->leg[j] = ptr->leg[j-1]; } else { if ( j ) last-> lege[j] = ptr->lege[j] = team_buf.leg[j].elapsed; last->leg[j] = ptr->leg[j] = team_buf.leg[j].end; ptr->lege[0] += ptr->lege[j] ; last->lege[0] = ptr->lege[0] ; } } last->start = ptr->start = team_buf.leg[0].start; ptr->class = config.nonequestrian_class; ptr->flags = team_buf.flags; ptr->flags.disqualified = 0; ptr++; sort_num++; } #endif } } } return ( TRUE ); } /*======================================================================== * * Generate all the stats * * Purpose: * This function is called to Generate all the stats * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void gen_stats(void) { ty_s_data *ptr; unsigned i; int j; int k; /* * Init all the stats */ for( i = 0; i <= MAX_LEGS; i++ ) { for( j = 0; j <= MAX_CLASS; j++ ) { stats.team[i][j] = 0; stats.fast.team[i][j] = 0; stats.fast.time[i][j] = ( time_t ) - 1; stats.average[i][j] = 0; } } for( i = 1, ptr = sort_data; i <= sort_num; i++, ptr++ ) { /* ** If there is any bad times in the team record, then none ** of the data can be trusted. ** ** If the team has been disqualified, then don't use any ** of the data. */ if( ptr->flags.bad_times || ptr->flags.disqualified ) continue; for( j = 0; j <= config.num_legs; j++ ) { if( ptr->lege[j] <= 0 ) /* Ignore bad data */ continue; /* ** Determine fastest team : overall ** Ignore the non-equestrian data as this is in the list twice */ if( ( ptr->lege[j] < stats.fast.time[j][0] ) || ( stats.fast.time[j][0] < 0 ) ) { if ( ptr->class != config.nonequestrian_class ) { stats.fast.team[j][0] = ptr->team; stats.fast.time[j][0] = ptr->lege[j]; } } /* ** Determine fastest team : within a class */ if( ( ptr->lege[j] < stats.fast.time[j][ptr->class] ) || stats.fast.time[j][ptr->class] < 0 ) { stats.fast.team[j][ptr->class] = ptr->team; stats.fast.time[j][ptr->class] = ptr->lege[j]; } /* ** Sum the end times : overall */ if ( ptr->class != config.nonequestrian_class ) { stats.average[j][0] += ptr->lege[j]; stats.team[j][0]++; } /* ** Sum the end times : within a class */ stats.average[j][ptr->class] += ptr->lege[j]; stats.team[j][ptr->class]++; } } /* * Calculate the averages */ for( k = 0; k <= config.num_legs; k++ ) { for( j = 0; j <= config.num_class; j++ ) { if( stats.team[k][j] ) stats.average[k][j] /= stats.team[k][j]; else stats.average[k][j] = ( time_t ) - 1; } } } /********************************* EOF ***********************************/