/************************************************************************* * 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 * px_place - Return place data with NE and V indication * 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 #include "consts.h" #include "structs.h" #include "proto.h" #include "mainwindow.h" void pri_awards_html(void); void pri_summary_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 ); #define MAX_PLACE 11 const char * place_text[] = { "Zero'th", "First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth", "Ninth", "Tenth", "Eleventh" }; int sort_leg; int sort_mode; bool sort_withEquestrian; bool sort_afterEquestrianLeg; 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 */ #define S_LC_NE 8 /* Elapsed times per class, with NE sorted by real class */ #define S_IFIN 9 /* Sort on elapsed time at given leg */ /* ** 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 int sort_num; /* Number in the array */ unsigned int sort_num_data; /* Number in the array */ ty_stats stats; /* Holds statistics */ /*======================================================================== * * 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; team_type team_buf; 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 ) setHref( "", url_encode(p_filename(filebase, "finish" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); print( " %-*s ", MAX_TM_NAME, team_buf.name ); if ( report_html == html ) setHref( "",url_encode(p_filename(filebase, config.team_class[team_buf.teamclass - 1].abr ,"html")), team_buf.numb ); print( "%-*s", LEN_CLASS_NAME, team_buf.teamclass == 0 ? "" : config.team_class[team_buf.teamclass - 1].full_name ); 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_body( void ) { ty_s_namedata *ptr; team_type team_buf; unsigned num; int i; unsigned int 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 ) { MainWindow::showMessage("Error in allocating memory"); 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->teamclass = team_buf.teamclass; 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->teamclass = team_buf.teamclass; 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 ) setHref( "", url_encode(p_filename(filebase, "finish" ,"html")), ptr->team ); print( "%*d", 6, ptr->leg + 1 ); print( " " ); if ( report_html == html ) setHref( "", url_encode(p_filename(filebase, "name" ,"html")), ptr->team ); print( "%*d", 5, ptr->team ); print( " " ); if ( report_html == html ) setHref( "",(p_filename(filebase, config.team_class[ptr->teamclass - 1].abr ,"html")), ptr->team ); print( "%-*s", LEN_CLASS_NAME, ptr->teamclass == 0 ? "" : config.team_class[ptr->teamclass - 1].abr ); 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_body(int leg) { ty_s_data *ptr; int i, k; /* * Sort the data in finishing order */ ck_data( leg, C_END ); /* Check data for this leg */ sort_team_data( leg, S_FIN, true ); /* 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" ); } 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 ", px_place(-1, ptr->place, false, false, ptr->flags ), 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, px_place( -1, ptra->place, false, false, ptra->flags ), 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: * leg - Leg number to print * * Returns: * Nothing * *========================================================================*/ void pri_eleg_body( int leg) { ty_s_data *ptr; int i, k; /* * Sort the data in finishing order */ ck_data( leg, C_ELAPSED ); /* Check data for this leg */ sort_team_data( leg, S_IFIN, true ); /* 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: Place:Team:ElapsedTime // * // * 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 ", px_place( -1, ptr->place, false, false, ptr->flags ), 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, px_place( -1, ptra->place, false, false, ptra->flags ), 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(); pri_final_teamOrder(); report_html = printed; pri_final(); pri_final_teamOrder(); 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; team_type team_buf; unsigned i; int j, last_class; char *report_title; bool class_done[MAX_CLASS+1]; int lcount; bool isNeClass = false; ck_data( -1, C_ELAPSED ); /* ** Sort on every thing ** Then generate all the stats too */ do_big_sort(); gen_stats(); /* * Now print the data on the printer */ if( !open_printer( "", "finish", 132, report_html, "Finishing Order" ) ) return; /* * Print out the data */ print_class_header( -1, TRUE ); /* Print the header */ sort_team_data( 0, S_L, true ); /* Re-sort on elapsed time */ lcount = 0; for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { if ( ptr->isNeData ) continue; g_record( ptr->team, &team_buf ); /* ** If this is a NE team then dummy up some of the data that hasn't been stored in team_buf */ if (ptr->flags.non_equestrian) { team_buf.leg[0].l_place = sort_aux[ptr->team].leq_place[0]; team_buf.leg[0].lc_place = sort_aux[ptr->team].lq_place[0]; } /* ** 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 ", px_place( 0, team_buf.leg[0].l_place, false, true, ptr->flags ) ); if ( report_html == html ) setHref( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); print( " %-*s", 3, team_buf.teamclass == 0 ? "" : config.team_class[team_buf.teamclass - 1].abr ); /* ** Print the per-leg data ** - Time ** - Leg place ** - End place */ for( j = 1; j <= config.num_legs; j++ ) { bool isEquestrianLeg = (j == config.equestrian_leg && team_buf.flags.non_equestrian); /* ** Ensure that non-equestrian leg data is not displayed */ if ( isEquestrianLeg ) { print( " %-8s %4.4s %4.4s", "-- NE --", "NE","NE"); } else { print( " %-8s", time_a( team_buf.leg[j].elapsed )); if ( config.num_legs != 1 ) print( " %4.4s", px_place( j, team_buf.leg[j].l_place, false, false, ptr->flags )); if ( config.num_legs != 1 ) print( " %4.4s", px_place( j, team_buf.leg[j].le_place,true , true, ptr->flags )); if ( config.num_legs == 1 ) print( " %-*s ", MAX_TM_NAME, team_buf.name ); } } /* ** Print the trailer (Finishing order) ** - Total time ** - Category place - with reference to category file */ if ( config.num_legs != 1 ) print( " %-8s ", time_a( ptr->lege[0] ) ); if ( report_html == html ) setHref( "",url_encode(p_filename(filebase, config.team_class[team_buf.teamclass - 1].abr ,"html")), team_buf.numb ); print( "%4.4s", px_place( 0, team_buf.leg[0].lc_place, false, false, ptr->flags) ); 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 */ /* ------------------ Class Reports * Now produce a breakdown on a class by class basis * Now print out the class placement information */ sort_team_data( 0, S_LC, true ); /* 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++ ) { short teamClass = ptr->teamclass; isNeClass = false; /* ** Dummy up the psuedo NE data a little bit */ if (ptr->isNeData) { isNeClass = true; teamClass = config.nonequestrian_class; } //qDebug() << "NEtm:" << ptr->team << "," << isNeClass << "," << teamClass; /* ** 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 != teamClass ) { if( last_class >= 0 ) { print_class_stats( last_class, TRUE ); print_legend( last_class, 1 ); close_printer(); if (class_done[teamClass]) { qDebug() << "ERROR class already processed - order error"; } last_class = 0; } report_title = tprintf( "Category results for : %-*s", LEN_CLASS_NAME, teamClass == 0 ? "" : config.team_class[teamClass - 1].full_name ); if( !open_printer( "", config.team_class[teamClass - 1].abr, 132, report_html, report_title ) ) continue; print_class_header( last_class = teamClass, TRUE ); /* ** Mark the class as done */ class_done[teamClass] = TRUE; lcount = 0; last_class = teamClass; } /* ** Now read in the team record */ g_record( ptr->team, &team_buf ); /* ** Dummy up the data for the dummy nonEquestrian Class ** Its not stored in the team_buf for backwards compatability */ if( isNeClass) { for( j = 0; j <= config.num_legs; j++ ) { team_buf.leg[j].lc_place = sort_aux[ptr->team].lq_place[j]; team_buf.leg[j].lec_place = sort_aux[ptr->team].leq_place[j]; } } else { if (ptr->flags.non_equestrian) { //team_buf.leg[0].lc_place = sort_aux[ptr->team].lcq_place[0]; //team_buf.leg[0].lc_place = sort_aux[ptr->team].lcq_place[0]; team_buf.leg[0].lec_place = sort_aux[ptr->team].leq_place[0]; } } /* ** 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 ", px_place( 0, team_buf.leg[0].lc_place, false, false, ptr->flags) ); if ( report_html == html ) setHref( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); print( " %-*s", 3, team_buf.teamclass == 0 ? "" : config.team_class[team_buf.teamclass - 1].abr ); for( j = 1; j <= config.num_legs; j++ ) { bool isEquestrianLeg = (j == config.equestrian_leg && (ptr->isNeData || ptr->flags.non_equestrian)); /* ** Ensure that non-equestrian leg data is not displayed */ if ( isEquestrianLeg ) { print( " %-8s %4.4s %4.4s", "-- NE --", "NE","NE"); } else { print( " %-8s", time_a( team_buf.leg[j].elapsed )); if ( config.num_legs != 1 ) print( " %4.4s", px_place( j, team_buf.leg[j].lc_place, false, false, ptr->flags )); if ( config.num_legs != 1 ) print( " %4.4s", px_place( j, team_buf.leg[j].lec_place, true , true, ptr->flags ) ); if ( config.num_legs == 1 ) print( " %-*s ", MAX_TM_NAME, team_buf.name ); } } #if 0 // zzz print (" --"); print (",%4.4d", sort_aux[ptr->team].l_place[0]); print (" %4.4d", sort_aux[ptr->team].l_place[1]); print (" %4.4d", sort_aux[ptr->team].l_place[2]); print (" %4.4d", sort_aux[ptr->team].l_place[3]); print (" %4.4d", sort_aux[ptr->team].l_place[4]); print (" %4.4d", sort_aux[ptr->team].l_place[5]); print (",%4.4d", sort_aux[ptr->team].le_place[0]); print (" %4.4d", sort_aux[ptr->team].le_place[1]); print (" %4.4d", sort_aux[ptr->team].le_place[2]); print (" %4.4d", sort_aux[ptr->team].le_place[3]); print (" %4.4d", sort_aux[ptr->team].le_place[4]); print (" %4.4d", sort_aux[ptr->team].le_place[5]); print (",%4.4d", sort_aux[ptr->team].lc_place[0]); print (" %4.4d", sort_aux[ptr->team].lc_place[1]); print (" %4.4d", sort_aux[ptr->team].lc_place[2]); print (" %4.4d", sort_aux[ptr->team].lc_place[3]); print (" %4.4d", sort_aux[ptr->team].lc_place[4]); print (" %4.4d", sort_aux[ptr->team].lc_place[5]); print (",%4.4d", sort_aux[ptr->team].lec_place[0]); print (" %4.4d", sort_aux[ptr->team].lec_place[1]); print (" %4.4d", sort_aux[ptr->team].lec_place[2]); print (" %4.4d", sort_aux[ptr->team].lec_place[3]); print (" %4.4d", sort_aux[ptr->team].lec_place[4]); print (" %4.4d", sort_aux[ptr->team].lec_place[5]); print (",%4.4d", sort_aux[ptr->team].lq_place[0]); print (" %4.4d", sort_aux[ptr->team].lq_place[1]); print (" %4.4d", sort_aux[ptr->team].lq_place[2]); print (" %4.4d", sort_aux[ptr->team].lq_place[3]); print (" %4.4d", sort_aux[ptr->team].lq_place[4]); print (" %4.4d", sort_aux[ptr->team].lq_place[5]); print (",%4.4d", sort_aux[ptr->team].leq_place[0]); print (" %4.4d", sort_aux[ptr->team].leq_place[1]); print (" %4.4d", sort_aux[ptr->team].leq_place[2]); print (" %4.4d", sort_aux[ptr->team].leq_place[3]); print (" %4.4d", sort_aux[ptr->team].leq_place[4]); print (" %4.4d", sort_aux[ptr->team].leq_place[5]); print (",[%4.4d", sort_aux[ptr->team].lcq_place[0]); print (" %4.4d", sort_aux[ptr->team].lcq_place[1]); print (" %4.4d", sort_aux[ptr->team].lcq_place[2]); print (" %4.4d", sort_aux[ptr->team].lcq_place[3]); print (" %4.4d", sort_aux[ptr->team].lcq_place[4]); print (" %4.4d]", sort_aux[ptr->team].lcq_place[5]); print (",%4.4d", sort_aux[ptr->team].lecq_place[0]); print (" %4.4d", sort_aux[ptr->team].lecq_place[1]); print (" %4.4d", sort_aux[ptr->team].lecq_place[2]); print (" %4.4d", sort_aux[ptr->team].lecq_place[3]); print (" %4.4d", sort_aux[ptr->team].lecq_place[4]); print (" %4.4d", sort_aux[ptr->team].lecq_place[5]); #endif /* ** Print the trailer ** - Total time ** - Overall place - with reference to overall place file */ if ( config.num_legs != 1 ) print( " %-8s ", time_a( ptr->lege[0] ) ); if ( report_html == html ) setHref( "", url_encode(p_filename(filebase, "finish" ,"html")), team_buf.numb ); print( "%4.4s", px_place( 0, team_buf.leg[0].l_place, false, true, ptr->flags)); 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] || !config.team_class[j-1].abr[0] ) { 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 == html || report_html == printed) { pri_team(); } /* ** Generate the awards report. ** This is only available as an HTML report */ if ( report_html == html || report_html == printed) { pri_awards_html(); } /* ** Generate the master index page */ if ( report_html == html ) { pri_master_index(); } pri_name_index_body(); } /*======================================================================== * * Print final results in Team Order * * Purpose: * This function is called to Print final results in Team Order * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_final_teamOrder(void) { ty_s_data *ptr; team_type team_buf; unsigned i; int j; int lcount; ck_data( -1, C_ELAPSED ); /* ** Sort on every thing ** Then generate all the stats too */ do_big_sort(); gen_stats(); /* * Now print the data on the printer */ if( !open_printer( "", "team_order", 132, report_html, "Team Order" ) ) return; /* * Print out the data */ print_class_header( -1, TRUE ); /* Print the header */ ptr = sort_data; sort_team_data( 0, S_TEAM, true ); /* Re-sort on team number */ lcount = 0; for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { if ( ptr->isNeData ) continue; g_record( ptr->team, &team_buf ); /* ** If this is a NE team then dummy up some of the data that hasn't been stored in team_buf */ if (ptr->flags.non_equestrian) { team_buf.leg[0].l_place = sort_aux[ptr->team].leq_place[0]; //team_buf.leg[0].lc_place = sort_aux[ptr->team].lcq_place[0]; } /* ** 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 ", px_place( 0, team_buf.leg[0].l_place, false, true, ptr->flags ) ); if ( report_html == html ) setHref( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); print( " %-*s", 3, team_buf.teamclass == 0 ? "" : config.team_class[team_buf.teamclass - 1].abr ); /* ** Print the per-leg data ** - Time ** - Leg place ** - End place */ for( j = 1; j <= config.num_legs; j++ ) { bool isEquestrianLeg = (j == config.equestrian_leg && team_buf.flags.non_equestrian); /* ** Ensure that non-equestrian leg data is not displayed */ if ( isEquestrianLeg ) { print( " %-8s %4.4s %4.4s", "-- NE --", "NE","NE"); } else { print( " %-8s", time_a( team_buf.leg[j].elapsed )); if ( config.num_legs != 1 ) print( " %4.4s", px_place(j, team_buf.leg[j].l_place, false, false, ptr->flags )); if ( config.num_legs != 1 ) print( " %4.4s", px_place(j, team_buf.leg[j].le_place,true, true, ptr->flags ) ); if ( config.num_legs == 1 ) print( " %-*s ", MAX_TM_NAME, team_buf.name ); } } /* ** Print the trailer (Finishing order) ** - Total time ** - Category place - with reference to category file */ if ( config.num_legs != 1 ) print( " %-8s ", time_a( ptr->lege[0] ) ); if ( report_html == html ) setHref( "",url_encode(p_filename(filebase, config.team_class[team_buf.teamclass - 1].abr ,"html")), team_buf.numb ); print( "%4.4s", px_place( 0, team_buf.leg[0].lc_place, false, false, ptr->flags ) ); //print (" --"); //print (" %4.4d", sort_aux[ptr->team].lq_place[0]); //print (" %4.4d", sort_aux[ptr->team].leq_place[0]); //print (" %4.4d", sort_aux[ptr->team].lcq_place[0]); //print (" ,%4.4d", sort_aux[ptr->team].lec_place[0]); //print (" %4.4d", sort_aux[ptr->team].lec_place[1]); //print (" %4.4d", sort_aux[ptr->team].lec_place[2]); //print (" %4.4d", sort_aux[ptr->team].lec_place[3]); //print (" %4.4d", sort_aux[ptr->team].lec_place[4]); //print (" %4.4d", sort_aux[ptr->team].lec_place[5]); //print (" ,%4.4d", sort_aux[ptr->team].lecq_place[0]); //print (" %4.4d", sort_aux[ptr->team].lecq_place[1]); //print (" %4.4d", sort_aux[ptr->team].lecq_place[2]); //print (" %4.4d", sort_aux[ptr->team].lecq_place[3]); //print (" %4.4d", sort_aux[ptr->team].lecq_place[4]); //print (" %4.4d", sort_aux[ptr->team].lecq_place[5]); 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 */ } /*======================================================================== * * 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 = printed; 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; team_type team_buf; int last_class; char solid_line[100]; bool header_done = false; bool entryFound; /* ** 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 - Full Event"); for( j = 1; j <= config.num_class; j++ ) { /* ** Header for the class */ if (!config.team_class[j - 1].abr[0]) continue; if (config.class_winners[j - 1] <= 0) continue; winmax = config.class_winners[j-1]; { int valid = sdata.teamclass[j].valid_ev; if ( valid < winmax ) winmax = valid; } print( "\n"); print( " "); if ( report_html == html ) setHref( "",url_encode(config.team_class[j-1].full_name)); print( "%s", tprintf( "%-*s", LEN_CLASS_NAME ,config.team_class[j-1].full_name )); print( " %3d Awards", winmax ); if ( config.class_winners[j-1] != winmax ) print( " from a maximum of %3d", config.class_winners[j-1] ); } /* ** NE Award Categories */ if ( config.class_ne_winners_by_class ) { print( "\n"); print( "Award Categories - Non Equestrian"); for( j = 1; j <= config.num_class; j++ ) { /* ** Header for the class */ if (!config.team_class[j - 1].abr[0]) continue; if ( config.class_ne_winners[j-1] <= 0 ) continue; winmax = config.class_ne_winners[j-1]; { int valid = sdata.teamclass[j].valid_ne; if ( valid < winmax ) winmax = valid; } print( "\n"); print( " "); if ( report_html == html ) setHref( "",url_encode(config.team_class[j-1].full_name)); print( "%s", tprintf( "%-*s", LEN_CLASS_NAME ,config.team_class[j-1].full_name )); print( " %3d Awards", winmax ); if ( config.class_ne_winners[j-1] != winmax ) print( " from a maximum of %3d", config.class_ne_winners[j-1] ); } } /* ** Manual entries */ print( "\n"); print( "Miscellaneous"); print( "\n"); print( " "); if ( report_html == html ) setHref( "",url_encode("Full Event")); print( "%s", tprintf( "%-*s", LEN_CLASS_NAME ,"Full Event")); print (" by Category"); if ( config.class_ne_winners_by_class ) { print( "\n"); print( " "); if ( report_html == html ) setHref( "",url_encode(config.team_class[config.nonequestrian_class-1].full_name)); print( "%s", tprintf( "%-*s", LEN_CLASS_NAME ,config.team_class[config.nonequestrian_class-1].full_name )); print (" by Category"); } print( "\n"); print( " "); if ( report_html == html ) setHref( "",url_encode("Hall Of Fame")); print( "%s", "Hall Of Fame" ); if (config.awardsfilename[0]) { print( "\n"); print( " "); if ( report_html == html ) setHref( "",url_encode("Additional Awards")); print( "%s", "Additional Awards" ); } print( "\n"); print( " "); if ( report_html == html ) setHref( "",url_encode("FASTEST")); print( "%s", "FASTEST" ); /* ---------------------------- Awards for Teams ---- ** Sort the data by class */ sort_team_data( 0, S_LC, true ); /* Generate class placement data */ last_class = -1; /* Invalid class to start with */ /* ** Process each category */ print( "\n"); entryFound = false; for( j = 1; ; j++ ) { if (!config.team_class[j - 1].abr[0]) continue; /* ** Tail for previous entry */ //if ( config.class_ne_winners_by_class && j == config.nonequestrian_class ) // continue; if ( j != 1 ) { if (!entryFound) { print( "\n"); print( "No winners awarded. Non eligible." ); if ( report_html == html ) print("
"); } 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( "
" ); if ( !header_done ) { header_done = true; if ( report_html == html ) { print( "",url_encode("Full Event")); } } print( "",url_encode(config.team_class[j-1].full_name)); } else { print( "%s\n", solid_line); } print( "Category: "); if ( report_html == html ) setHref( "",url_encode(p_filename(filebase, config.team_class[j - 1].abr ,"html"))); print( "%s", config.team_class[j-1].full_name ); if ( config.class_winners[j-1] <= 0 ) { print( "\n"); print( "No winners awarded" ); if ( report_html == html ) print("
"); continue; } /* ** Enties for 'n' the best teams as configured */ windex = 0; /* Winners done */ entryFound = false; unsigned int i; for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { if ( ptr->teamclass != 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 || ptr->flags.disqualified || ptr->flags.vet_check || !ptr->flags.valid ) break; if ( !ptr->isNeData && ptr->flags.non_equestrian ) break; /* ** Count the entry */ windex++; entryFound = true; /* ** 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 ) setHref( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%-*s ", MAX_TM_NAME, team_buf.name ); print( " Number: "); if ( report_html == html ) setHref( "", url_encode(p_filename(filebase, "finish" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); for( k = 0; k < MAX_MEMB; k++ ) { /* ** Skip equestrian leg in the non-equestion display */ if ( k + 1 == config.equestrian_leg && ptr->isNeData) 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; } } } /* ** Non Equestrian winners by category */ if ( config.class_ne_winners_by_class) { header_done = false; /* ** Sort the data by class with NE data sorted by real class */ sort_team_data( 0, S_LC_NE, true ); /* Generate class placement data */ last_class = -1; /* Invalid class to start with */ /* ** Only process the Non Equestrian teams in this pass */ print( "\n"); entryFound = false; for( j = 1; ; j++ ) { if (!config.team_class[j - 1].abr[0]) continue; /* ** Tail for previous entry */ if ( j == config.nonequestrian_class) continue; if ( j != 1 ) { if (!entryFound) { print( "\n"); print( "No winners awarded. Non eligible." ); if ( report_html == html ) print("
"); } if ( report_html == html ) print( "
Awards Index",url_encode("INDEX")); } if ( j > config.num_class ) break; /* ** Header for the (sub) class */ if ( !header_done ) { header_done = true; if ( report_html == html ) { print( "",url_encode(config.team_class[config.nonequestrian_class-1].full_name)); } } 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 ) setHref( "",url_encode(p_filename(filebase, config.team_class[config.nonequestrian_class - 1].abr ,"html"))); print( "%s", config.team_class[config.nonequestrian_class-1].full_name ); print (" :: "); if ( report_html == html ) setHref( "",url_encode(p_filename(filebase, config.team_class[j - 1].abr ,"html"))); print( "%s", config.team_class[j-1].full_name ); if ( config.class_ne_winners[j-1] <= 0 ) { print( "\n"); print( "No winners awarded" ); if ( report_html == html ) print("
"); continue; } /* ** Enties for 'n' the best teams as configured */ entryFound = false; windex = 0; /* Winners done */ unsigned int i; for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { if ( !ptr->isNeData ) continue; if ( ptr->teamclass != j ) { continue; } //qDebug() << "NeTeam0:" << ptr->team << "," << ptr->isNeData << "," << ptr->teamclass << "," << j; /* ** 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 || ptr->flags.disqualified || ptr->flags.vet_check || !ptr->flags.valid ) break; if ( /*!ptr->isNeData &&*/ !ptr->flags.non_equestrian ) break; /* ** Count the entry */ windex++; entryFound = true; /* ** 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 ) setHref( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%-*s ", MAX_TM_NAME, team_buf.name ); print( " Number: "); if ( report_html == html ) setHref( "", url_encode(p_filename(filebase, "finish" ,"html")), team_buf.numb ); print( "%4d", team_buf.numb ); for( k = 0; k < MAX_MEMB; k++ ) { /* ** Skip equestrian leg in the non-equestion display */ if ( k + 1 == config.equestrian_leg && ptr->isNeData) 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_ne_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 { qDebug( "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")); /* ** Insert additional Awards information */ if (config.awardsfilename[0]) { print( "\n"); if ( report_html == html ) { print( "
" ); print( "",url_encode("Additional Awards")); } else { print( "%s\n", solid_line); } print( "%s", "Additional Awards" ); print ("\n"); /* ** Read and process the named awards file */ FILE *adfile = NULL; char line[201]; QString name = QmConfig::getAddendemFile(config.awardsfilename); if (! name.isEmpty()) { adfile = fopen( qPrintable(name), "rt" ); /* Open the file for reading */ } if( adfile ) { while( fgets( line, sizeof(line)-1, adfile ) ) { // Process each line // Attempt to perform some smart text replacements // ie: print( "%s", line ); } fclose(adfile); } else { if ( report_html == html ) print ("
"); print( "\nThe awards file could not be found: %s\n", adfile); } 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 ) setHref( "", url_encode(p_filename(filebase, "name" ,"html")), team_buf.numb ); print( "%-*s", MAX_PERSON_NAME, team_buf.members[i-1].name ); print( " Team:"); if ( report_html == html ) setHref( "", url_encode(p_filename(filebase, "finish" ,"html")), team_buf.numb ); print( "%4d" , stats.fast.team[i][0] ); 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(const char *name, const 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( "team_order", "All Teams with results" ); pri_master_index_entry( "awards", "Prizes and Awards" ); print( "
\n" ); print( "\n" ); for( j = 1; j <= config.num_class; j++ ) { if (!config.team_class[j - 1].abr[0]) continue; 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( "team_order", "All Teams with results" ); pri_master_index_entry( "awards", "Prizes and Awards" ); print( "
\n" ); print( "\n" ); pri_master_index_entry( "summary", "Category Summary" ); for( j = 1; j <= config.num_class; j++ ) { if (!config.team_class[j - 1].abr[0]) continue; 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 ( int 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 ( int 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(); /* ** Tell the main system about this new report */ MainWindow::registerReport(getPrinterFile(), "Master Leg Index"); } /*======================================================================== * * Print interim results * * Purpose: * This function is called to Print interim results * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_interim(void) { ty_s_data *ptr; team_type team_buf; unsigned i; int j, last_class; char *report_title; short pClass; if ( ! report_all ) { ck_data( -1, C_DISQUAL ); /* Check the data - dummy check */ } do_big_sort(); /* Sort on every thing */ gen_stats(); /* Generate the stats too */ /* * 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, true ); /* Re-sort on team number */ for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { if ( ptr->isNeData ) continue; g_record( ptr->team, &team_buf ); print( "%4d %4.4s %-*s", team_buf.numb, px_place(-1, team_buf.leg[config.num_legs].le_place, false, false, ptr->flags ), 3, team_buf.teamclass == 0 ? "" : config.team_class[team_buf.teamclass - 1].abr ); for( j = 1; j <= config.num_legs; j++ ) { print( " %-8s", time_fa( team_buf.leg[j].elapsed, ptr->flags.disqualified )); if ( config.num_legs != 1 ) print( " %4.4s", px_place(j, team_buf.leg[j].l_place, false, true, ptr->flags )); if ( config.num_legs != 1 ) print( " %4.4s", px_place(j, team_buf.leg[j].le_place, false, true, ptr->flags )); if ( config.num_legs == 1 ) print( " %-*s ", MAX_TM_NAME, team_buf.name ); } if ( config.num_legs != 1 ) print( " %-8s", time_fa( team_buf.leg[0].elapsed, ptr->flags.disqualified )); print( " %4.4s\n", px_place(0, team_buf.leg[config.num_legs].lec_place, false, false, ptr->flags )); } 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 */ sort_team_data( 0, S_CLASS, true ); /* Generate class placement data */ last_class = -1; /* Invalid class to start with */ pClass = -1; for( ptr = sort_data, i = 0; i < sort_num; i++, ptr++ ) { if (ptr->isNeData) pClass = config.nonequestrian_class; else pClass = ptr->teamclass; /* ** 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 != pClass ) { if( last_class >= 0 ) { print_class_stats( last_class, FALSE ); print_legend(last_class, 1); close_printer(); } report_title = tprintf( "Interim Category results for : %-*s", LEN_CLASS_NAME, pClass == 0 ? "" : config.team_class[pClass - 1].full_name ); if( !open_printer( "", tprintf( "i%2s", config.team_class[pClass - 1].abr ), 132, report_html, report_title ) ) continue; print_class_header( last_class = pClass, FALSE ); } /* ** Now read in the team record */ g_record( ptr->team, &team_buf ); print( "%4d %4.4s %-*s", team_buf.numb, px_place(-1, team_buf.leg[config.num_legs].lec_place, false, false, ptr->flags ), 3, team_buf.teamclass == 0 ? "" : config.team_class[team_buf.teamclass - 1].abr ); for( j = 1; j <= config.num_legs; j++ ) { print( " %-8s", time_fa( team_buf.leg[j].elapsed, ptr->flags.disqualified )); if ( config.num_legs != 1 ) print( " %4.4s", px_place(j, team_buf.leg[j].lc_place, false, true, ptr->flags )); if ( config.num_legs != 1 ) print( " %4.4s", px_place(j, team_buf.leg[j].lec_place, false, true, ptr->flags )); if ( config.num_legs == 1 ) print( " %-*s ", MAX_TM_NAME, team_buf.name ); } if ( config.num_legs != 1 ) print( " %-8s", time_fa( team_buf.leg[0].elapsed, ptr->flags.disqualified )); print( " %4.4s\n", px_place(0, team_buf.leg[config.num_legs].le_place, false, false, ptr->flags ) ); } 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; team_type team_buf; /* ** Sort on every thing ** Then generate all the stats too */ do_big_sort(); gen_stats(); /* * Now print the data on the printer */ if( !open_printer( "full_data", "csv", 2000, text, NULL ) ) return; /* ** 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", "NE Leg Place"); csv_print( "%s", "NE Leg End Place"); csv_print( "%s", "NE Leg Class Place"); csv_print( "%s", "NE 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 Leg End Place"); csv_print( "%s", "Team Event Place"); csv_print( "%s", "Team Leg Class Place"); csv_print( "%s", "Team Event Class Place"); csv_print( "%s", "NE Team Leg End Place"); csv_print( "%s", "NE Team Event Place"); csv_print( "%s", "NE Team Leg Class Place"); csv_print( "%s", "NE Team Event Class Place"); 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( "%s", "Flag:vet_check" ); // Not available as the data is only in-memory // csv_print( "%s", "Flag:notInFastest" ); // csv_print( "%s", "Flag:notInSort" ); 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.teamclass == 0 ? "" : config.team_class[team_buf.teamclass - 1].full_name ); csv_print( "%s", team_buf.teamclass == 0 ? "" : config.team_class[team_buf.teamclass - 1].abr ); csv_print( "%s", time_a (team_buf.teamclass == 0 ? 0 : config.team_class[team_buf.teamclass - 1].start )); csv_print( "%d", team_buf.teamclass == 0 ? 0 : config.team_class[team_buf.teamclass - 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", sort_aux[team_buf.numb].lq_place[j] ); csv_print( "%d", sort_aux[team_buf.numb].leq_place[j] ); csv_print( "%d", sort_aux[team_buf.numb].lcq_place[j] ); csv_print( "%d", sort_aux[team_buf.numb].lecq_place[j] ); 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", sort_aux[team_buf.numb].lq_place[j] ); csv_print( "%d", sort_aux[team_buf.numb].leq_place[j] ); csv_print( "%d", sort_aux[team_buf.numb].lcq_place[j] ); csv_print( "%d", sort_aux[team_buf.numb].lecq_place[j] ); 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 ); csv_print( "%d", team_buf.flags.vet_check ); // Not available as the data is only in-memory // csv_print( "%d", team_buf.flags.notInFastest ); // csv_print( "%d", team_buf.flags.notInSort ); //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 = printed; // //pri_leg_body ( leg ); //pri_eleg_body ( leg ); report_html = text; } pri_final(); pri_final_teamOrder(); pri_final_html(); pri_csv_data(); pri_summary_html(); pri_summary(); pri_awards_html(); pri_awards(); pri_master_index(); report_html = html; pri_interim(); report_html = text; pri_interim(); 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 teamclass, 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 */ if (config.num_legs == 1 ) { print( "%-*s", 4, "" ); print( " %-*s", 18, config.leg_name[0] ); print( " %-*s", MAX_TM_NAME + 1, "" ); print( "%-4s\n", ( teamclass < 0 ) ? "Cat" : "Fin" ); } else { 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", ( teamclass < 0 ) ? "Cat" : "Fin" ); } /* ** Line-2 Details */ print_underline( TRUE ); print( "%-*s %*s %-*s", 4, final ? "Plce" : "Team", 4, final ? "Team" : "Plce", 3, "Cat" ); if (config.num_legs == 1 ) { print( " %-8s", "Time" ); print( " %-*s", MAX_TM_NAME + 1, "Team Name" ); print( "%4s\n", "Plce" ); } else { 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; const 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 ); } if ( config.num_legs != 1 ) { print_bold( TRUE ); print( "%-13s ", final ? "Total" : "" ); print_bold( FALSE ); } print( "\n" ); /* ** 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 ) setHref( "", url_encode(p_filename(filebase, "name" ,"html")), stats.fast.team[j][c] ); print( "%4d", stats.fast.team[j][c] ); print( " %s ", time_a( stats.fast.time[j][c] ) ); if ( config.num_legs == 1 ) break; } 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] ) ); if ( config.num_legs == 1 ) break; } } /*======================================================================== * * 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 teamclass, 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 (!config.team_class[i - 1].abr[0]) continue; if ( report_html == html ) setHref( "",url_encode(p_filename(filebase, config.team_class[i - 1].abr ,"html")) ); print( "%-*s", 3, config.team_class[i - 1].abr ); 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 ) { setHref( "", url_encode(p_filename(filebase, "finish" ,"html")) ); print( "%-*s", 3, "All" ); 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 ) { if ( config.num_legs != 1 ) { print( "\n" ); if ( report_html ) print_underline(TRUE); print( "Place numbers (LP and EP)" ); if ( report_html ) print_underline(FALSE); print( "\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" ); } else { print( "\n" ); if ( report_html ) print_underline(TRUE); print( "Table Legend" ); if ( report_html ) print_underline(FALSE); print( "\n" ); print( "Cat Plce - Placing within the category.\n"); print ("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] ) { QString name = QmConfig::getAddendemFile(config.addendum); if (! name.isEmpty()) { adfile = fopen( qPrintable(name), "rt" ); /* Open the file for reading */ } } if( adfile ) { while( fgets( line, sizeof(line)-1, adfile ) ) print( "%s", line ); fclose (adfile); } else { print( "\nTiming and Results by\n" ); print( "Embedded Solutions\n" ); } } /*======================================================================== * * Return place data or NE flag * * 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: * leg Leg number being processed or * -1: Unplaced on any bad flag * num place - if valid time * epMode true: Event Time Mode - Show V and NE flags * false: Leg Time Mode - * neMode true: Display NE for NE Teams * false: Display data for NE teams * flags Team flags * * Returns: * This function returns a pointer to the character string for the * number or a pointer to a status string. * *========================================================================*/ const char *px_place( int leg, int num, bool epMode, bool neMode, team_flags flags ) { static char store[2][5]; /* 2 stores for 4 digit numbers */ static int i = 0; /* Current index into store */ static const char *dis = "U"; static const char *alt = "NE"; static const char *vet = "U"; if (flags.bad_times || flags.disqualified || !flags.valid) return dis; if (leg == -1 && flags.vet_check ) return vet; if (neMode && flags.non_equestrian && (leg >= config.equestrian_leg || leg == 0)) return alt; if (epMode && flags.vet_check && leg >= config.equestrian_leg) return vet; if ( flags.vet_check && (leg == config.equestrian_leg || leg == 0)) return vet; if (num <= 0) return dis; i++; 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 * C_END - Printing in Leg Finishing Time * C_DISQUAL - Interim results * C_ELAPSED - Elapsed times * * *========================================================================*/ void ck_data( int leg, int mode ) { ty_s_data *ptr; unsigned i; int bad = 0; int k; int 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 the team is duff, then don;t include in Event or Leg Calcs if( !ptr->flags.valid || ptr->flags.bad_times || ptr->flags.disqualified) { ptr->flags.notInLP = TRUE; } else { // If any of the leg times are duff, then don't include the leg Event Calcs 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 ) { if ( ! report_all ) { qDebug( "Team with incorrect time information: %d", ptr->team ); bad++; } } } } if( bad ) { qDebug( "%d teams with incorrect times. These have been flagged as unplaced", bad ); } } /*======================================================================== * * 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) { ck_data( -1, C_ELAPSED ); do_big_sort(); /* * Generate the stats */ gen_stats(); } /*======================================================================== * * 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; team_type team_buf; /* ** 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 ) ) { bool valid = true; bool valid_ne = true; if ( team_buf.flags.disqualified ) { ptr->teamclass[team_buf.teamclass].disqualified++; ptr->total.disqualified++; valid = false; valid_ne = false; } if ( team_buf.flags.vet_check ) { ptr->teamclass[team_buf.teamclass].vet_check++; ptr->total.vet_check++; valid = false; valid_ne = false; } if ( config.nonequestrian_class && team_buf.flags.non_equestrian ) { ptr->teamclass[team_buf.teamclass].non_equestrian++; ptr->total.non_equestrian++; valid = false; } else { valid_ne = false; } ptr->total.total++; ptr->teamclass[team_buf.teamclass].total++; if ( valid ) { ptr->total.valid++; ptr->teamclass[team_buf.teamclass].valid++; if ( ! team_buf.flags.bad_times ) { ptr->total.valid_ev++; ptr->teamclass[team_buf.teamclass].valid_ev++; } } if ( valid_ne ) { if ( ! team_buf.flags.bad_times ) { ptr->total.valid_ne++; ptr->teamclass[team_buf.teamclass].valid_ne++; } } } } /* ** 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->teamclass[config.nonequestrian_class].total += ptr->total.non_equestrian; ptr->teamclass[config.nonequestrian_class].valid += ptr->teamclass[config.nonequestrian_class].total; } } /*======================================================================== * * Print summary results * * Purpose: * This function is called to Print summary results * Keep the page to 80 cols, so that it can be pronted on A4 * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void pri_summary_html(void) { report_type saved = report_html; /* ** Generate ALL results with HTML tags */ report_html = html; pri_summary(); report_html = printed; pri_summary(); report_html = saved; } /*======================================================================== * * 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; if( !open_printer( "", "summary", 80, report_html, "Summary Information" ) ) return; calc_class_summary( & data ); /* ** Display summary stats */ print( "%*s : %-7s %-7s %-7s %-7s %-7s %-7s %-7s\n", LEN_CLASS_NAME, "Category", "Total", "Valid", "Disq", "NonEq", "VetChk", "CompEv", "CompNe" ); for( i = 0; i < config.num_class; i++ ) { if (!config.team_class[i].abr[0]) continue; /* ** The non-equestrian leg does not have any data ** Suppress the display */ if ( config.nonequestrian_class == i+1 ) continue; if ( report_html == html ) setHref( "",url_encode(p_filename(filebase, config.team_class[i].abr ,"html")) ); print( "%*s ", LEN_CLASS_NAME, config.team_class[i].full_name ); print( ": %-7d %-7d %-7d %-7d %-7d %-7d %-7d\n", data.teamclass[i+1].total, data.teamclass[i+1].valid, data.teamclass[i+1].disqualified, data.teamclass[i+1].non_equestrian, data.teamclass[i+1].vet_check, data.teamclass[i+1].valid_ev, data.teamclass[i+1].valid_ne ); } print( "\n" ); print( "%*s : %-7d %-7d %-7d%-7d %-7d %-7d %-7d\n", LEN_CLASS_NAME, "Totals", data.total.total, data.total.valid, data.total.disqualified, data.total.non_equestrian, data.total.vet_check, data.total.valid_ev, data.total.valid_ne ); close_printer(); } /*======================================================================== * * 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, q; /* Looooopy things */ unsigned j; ty_s_data *ptr; /* Pointer to sort data */ int teamclass; /* Current class */ int teamclassq; /* Current class */ team_type team_buf; for( i = 0; i <= config.num_legs; i++ ) { bool sortWithEq = (i == 0); /* ** Sort on leg elapsed time ** Then save the teams elapsed place in each leg */ sort_team_data( i, S_L, sortWithEq ); for( j = 1, k = 1, q = 1, ptr = sort_data; j <= sort_num; ptr++, j++ ) { sort_aux[ptr->team].team = ptr->team; if (i == config.equestrian_leg || i == 0) { if (ptr->flags.bad_times || ptr->flags.disqualified || ptr->flags.vet_check) { if (ptr->isNeData) { sort_aux[ptr->team].lq_place[i] = -1; } else { sort_aux[ptr->team].l_place[i] = -1; } continue; } } // Flag as unplaced NE teams on the EQ leg // DO NOT Flag as unplaced in overall (leg:0) NE teams as this is used in the full report if ( (i == config.equestrian_leg /*|| i == 0*/ ) && ptr->flags.non_equestrian ) { if (ptr->isNeData) { sort_aux[ptr->team].lq_place[i] = -1; } else { sort_aux[ptr->team].l_place[i] = -1; } continue; } if (ptr->isNeData) { sort_aux[ptr->team].lq_place[i] = q++; } else { sort_aux[ptr->team].l_place[i] = k++; } } /* ** Sort on leg end time ** Then save the teams place at the end of each leg */ sort_team_data( i, S_LE, sortWithEq); for( j = 1, k = 1, q = 1, ptr = sort_data; j <= sort_num; ptr++, j++ ) { if (i == 0 || i == config.equestrian_leg || sort_afterEquestrianLeg ) { if (ptr->flags.bad_times || ptr->flags.disqualified || ptr->flags.vet_check) { if (ptr->isNeData) { sort_aux[ptr->team].leq_place[i] = -1; } else { sort_aux[ptr->team].le_place[i] = -1; } continue; } } // Flag as unplaced NE teams on the EQ leg // Flag as unplaced NE teams after the EQ leg // Flag as unplaced in overall (leg:0) NE teams if ( (i == config.equestrian_leg || sort_afterEquestrianLeg || i == 0 ) && ptr->flags.non_equestrian ) { if (ptr->isNeData) { sort_aux[ptr->team].leq_place[i] = -1; } else { sort_aux[ptr->team].le_place[i] = -1; } continue; } if (ptr->isNeData) { sort_aux[ptr->team].leq_place[i] = q++; } else { sort_aux[ptr->team].le_place[i] = k++; } } /* ** Sort on elapsed time per class ** Then save the teams elapsed place in each leg per class */ sort_team_data( i, S_LC, sortWithEq ); teamclass = -1; teamclassq = -1; int ll = -1; for( k = 1, j = 1, q = 1, ptr = sort_data; j <= sort_num; j++, ptr++ ) { bool isNe = false; if ( sortWithEq && ptr->isNeData ) { if ( !ptr->isNeData) isNe = true; } else { if (ptr->isNeData) isNe = true; } // Flag as unplaced NE teams on the EQ leg if (i == 0 || i == config.equestrian_leg) { if (ptr->flags.bad_times || ptr->flags.disqualified || ptr->flags.vet_check) { if (isNe) { sort_aux[ptr->team].lcq_place[i] = -1; } else { sort_aux[ptr->team].lc_place[i] = -1; } continue; } } if ( i == config.equestrian_leg && ptr->flags.non_equestrian ) { if (ptr->isNeData) { sort_aux[ptr->team].lcq_place[i] = -1; } else { sort_aux[ptr->team].lc_place[i] = -1; } continue; } if (ptr->isNeData) { if( teamclassq != ptr->teamclass ) { q = 1; teamclassq = ptr->teamclass; } //qDebug() << "Team:" << ptr->team << ",Class:" << ptr->teamclass << "," << q; sort_aux[ptr->team].lcq_place[i] = q++; } else { if( teamclass != ptr->teamclass ) { k = 1; ll = 1; teamclass = ptr->teamclass; } if (ptr->flags.non_equestrian && sortWithEq) sort_aux[ptr->team].lc_place[i] = ll++; else 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 ** Suuport NE teams as well Equestrian Teams */ sort_team_data( i, S_LEC, sortWithEq ); teamclass = -1; teamclassq = -1; for( k = 1, j = 1, q = 1, ptr = sort_data; j <= sort_num; j++, ptr++ ) { // All teams with bad data if (ptr->flags.bad_times || ptr->flags.disqualified ) { sort_aux[ptr->team].lec_place[i] = -1; sort_aux[ptr->team].lecq_place[i] = -1; continue; } // NE team - the full entry // Flag as unplaced NE teams on the EQ leg // Flag as unplaced NE teams after the EQ leg // Flag as unplaced in overall (leg:0) NE teams if (!ptr->isNeData && ptr->flags.non_equestrian) { if (i == 0 || i == config.equestrian_leg || sort_afterEquestrianLeg ) { sort_aux[ptr->team].lec_place[i] = -1; continue; } // NE Team - the duplicate entry // Flag as unplaced NE teams after the EQ leg } else if ( ptr->isNeData ) { if ( i == config.equestrian_leg) { sort_aux[ptr->team].lecq_place[i] = -1; continue; } // EQ Team // Flag as unplaced vetted teams on the EQ leg // Flag as unplaced vetted teams after the EQ leg // Flag as unplaced in overall (leg:0) vetted teams } else { if (i == 0 || i == config.equestrian_leg || sort_afterEquestrianLeg ) { if ( ptr->flags.vet_check) { sort_aux[ptr->team].lec_place[i] = -1; continue; } } } if (ptr->isNeData) { if( teamclassq != ptr->teamclass ) { q = 1; teamclassq = ptr->teamclass; } sort_aux[ptr->team].lecq_place[i] = q++; } else { if( teamclass != ptr->teamclass ) { k = 1; teamclass = ptr->teamclass; } sort_aux[ptr->team].lec_place[i] = k++; } } } /* ** Write the place information back to disk for use in the displays ** For backwards compatability we havn't saved all the data. ** The NE specific data has not been saved, but is held in memory for report generation */ 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 * withEq Sort with equestrian data (True=Normal) * * Returns: * Nothing * *========================================================================*/ void sort_team_data( int leg, int mode, bool withEq ) { 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 */ sort_withEquestrian = withEq; /* Mode is global for compare function */ sort_afterEquestrianLeg = ( config.equestrian_leg && leg > config.equestrian_leg); 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; } //qDebug() << "sort_team_data: Leg:" << leg << ",M:" << mode << ",E:" << withEq; } /*======================================================================== * * 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 * Return negative if 'a' is less than 'b', * zero if 'a' == 'b' * positive if 'a' > 'b' * *========================================================================*/ int sort_comp( const void * aa, const void * bb ) { const ty_s_data * a = (ty_s_data *)aa; const ty_s_data * b = (ty_s_data *)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 ** Sort NE entries as a class of there own */ if( sort_mode == S_CLASS ) { if ( a->isNeData || b->isNeData) { if ( a->isNeData && b->isNeData) return ( a->team - b->team ); else return ( a->isNeData ? 1 : -1 ); } if( a->teamclass != b->teamclass ) return ( a->teamclass - b->teamclass ); else return ( a->team - b->team ); } /* ** Sorting within a class ** First sort on the class ** Always put the NE entries last as this will simplify processing ** Compare NE entries against NE entries and EQ entries againstEQ entries */ if( sort_mode == S_LEC || sort_mode == S_LC /*|| sort_mode == S_LC_NE*/ ) { /* Sort within a class */ if ( a->isNeData || b->isNeData) { if ( !(a->isNeData && b->isNeData ) ) return ( a->isNeData ? 1 : -1 ); } else { if (a->teamclass != b->teamclass) { return ( a->teamclass - b->teamclass ); } } } /* ** 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 ** */ bool aNoSort = false; bool bNoSort = false; if ( sort_leg != 0 && (sort_mode == S_LC || sort_mode == S_L ) ) { aNoSort = a->flags.notInLP; bNoSort = b->flags.notInLP; } if ( sort_withEquestrian && (sort_mode == S_LC || sort_mode == S_L ) ) { if (a->flags.vet_check) aNoSort = true; if (b->flags.vet_check) bNoSort = true; } if (a->flags.bad_times || a->flags.disqualified || !a->flags.valid) aNoSort = true; if (b->flags.bad_times || b->flags.disqualified || !b->flags.valid) bNoSort = true; if ( sort_mode == S_FIN || sort_mode == S_IFIN ) { if (a->flags.vet_check) aNoSort = true; if (b->flags.vet_check) bNoSort = true; } if (sort_mode == S_IFIN ) { if (a->isNeData) aNoSort = true; if (b->isNeData) bNoSort = true; } // On the Equestrian Leg, vetted out teams are treated as disqualified if (sort_leg == config.equestrian_leg || (sort_afterEquestrianLeg && ( sort_mode == S_LE || sort_mode == S_LEC))) { if (a->flags.vet_check) aNoSort = true; if (b->flags.vet_check) bNoSort = true; } if (aNoSort && bNoSort) return ( a->team - b->team ); if (aNoSort || bNoSort) return ( aNoSort ? 1 : -1 ); if( sort_withEquestrian && sort_mode != S_FIN && sort_mode != S_IFIN ) { if( a->flags.non_equestrian && b->flags.non_equestrian ) { /* ** Both are non equestrian ** Let the time sort operate ... */ //return ( a->team - b->team ); } else if( a->flags.non_equestrian || b->flags.non_equestrian ) { /* One is equestrian */ /* Good times better than NE */ return ( a->flags.non_equestrian ? 1 : -1 ); } } /* ** 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_NE: case S_LC: case S_L: case S_IFIN: ta = a->lege[sort_leg]; tb = b->lege[sort_leg]; break; /* ** Just to be sure ... */ default: return ( 0 ); } if (sort_mode != S_LC_NE) { /* ** If we are ignore Equestrian config then place the Equestrian data last */ if (sort_withEquestrian) { if (a->isNeData != b->isNeData) return ( a->isNeData ? 1 : -1 ); } if ( a->team == b->team) { return ( a->isNeData ? 1 : -1 ); } } /* ** 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; unsigned j; unsigned num; team_type team_buf; /* * 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 ** OLD: Take a guess that at most 1/2 the teams will be non-equestrian ** NEW: Memory is cheap. Assume all teams could be non-equestrian */ // OLD: num = num * 3 / 2; num = num * 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 ) { MainWindow::showMessage("Error in allocating memory"); 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( int 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; ptr->isNeData = false; 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->teamclass = team_buf.teamclass; ptr->flags = team_buf.flags; // Add a few flags to simplify processing // Vetted out teams to be included inthe fastest calcs - except for Equestian Leg // Bodgey teams are not sorted by place - only after all places and then by team number ptr->flags.notInLP = 0; ptr->flags.notInFastest = 0; if ( ptr->flags.bad_times || ptr->flags.disqualified || !ptr->flags.valid) { ptr->flags.notInLP = 1; ptr->flags.notInFastest = 1; } 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->isNeData = true; ptr->lege[0] = 0; for( j = 0; j < MAX_LEGS + 1; j++ ) { if ( (short)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->teamclass = team_buf.teamclass; ptr->flags = team_buf.flags; ptr++; sort_num++; } #endif } } } #if 0 // Debug zzz qDebug() << "--- Start ---"; sort_team_data( 0, S_LC, 1 ); for( j = 1, ptr = sort_data; j <= sort_num; j++, ptr++ ) { qDebug() << "T:" << ptr->team << "Class:" << ptr->teamclass << "NEData:" << (ptr->isNeData? 1:0) << "iLP:" << (ptr->flags.notInLP ? 1:0) << "iF:" << (ptr->flags.notInFastest ? 1:0) << "Valid:" << (ptr->flags.valid ? 1:0) << "NE:" << (ptr->flags.non_equestrian? 1:0) << "B:" << (ptr->flags.bad_times ? 1 : 0 ) << "D:" << (ptr->flags.disqualified ? 1:0 ) << "V:" << (ptr->flags.vet_check ? 1:0 ) << "LE0:" << ptr->lege[0] << "L0:" << ptr->leg[0] << "LE1:" << ptr->lege[3] ; } qDebug() << "-----------------------------------End---"; #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.notInFastest) { continue; } short teamClass = ptr->teamclass; /* Don't include the psuedo NE data items in the calculations (unless processing NE class) ** They are duplicates of other data */ if (j == config.nonequestrian_class) { if ( !ptr->isNeData) continue; } if (ptr->isNeData) teamClass = config.nonequestrian_class; for( j = 0; j <= config.num_legs; j++ ) { if( ptr->lege[j] <= 0 ) /* Ignore bad data */ continue; /* ** If this is the Equestrian Leg and the team has been vetted out, then this team cannot ** be included into the stats for this leg ** ** If team has been vetted out then don't consider in fastest overall */ if ( ptr->flags.vet_check && (j == config.equestrian_leg || j== 0)) { continue; } /* If this is the Equestrian Leg and the team is a Non-Equestrian Team, then don't include ** it into the stats. ** ** If this is a NE team then don't consider it to be fastest overall */ if ( !ptr->isNeData && ptr->flags.non_equestrian && (j == config.equestrian_leg || j== 0)) { 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->isNeData ) { 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][teamClass] ) || stats.fast.time[j][teamClass] < 0 ) { stats.fast.team[j][teamClass] = ptr->team; stats.fast.time[j][teamClass] = ptr->lege[j]; } /* ** Sum the end times : overall */ if ( !ptr->isNeData ) { stats.average[j][0] += ptr->lege[j]; stats.team[j][0]++; } /* ** Sum the end times : within a class */ stats.average[j][teamClass] += ptr->lege[j]; stats.team[j][teamClass]++; } } /* * Calculate the averages * Can ignore that fact that some categories don't exists * The results will be -1 */ 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 ***********************************/