/************************************************************************* * Copyright (C) 1995 Embedded Solutions * All rights reserved * * file: src\legtime.c * * purpose: Leg time calculations * * functions * set_legs - Menu: Setup leg times * tm_lgs - Set up the leg start times for leg * leg_start - Set up the leg start times * tm_fixedstart - Set the start time for a specific leg * tm_staggered - Set a staggered start time for a specific leg * tm_clearleg - Clear start times on a specific leg * leg_ini - Initialize all stored times * tm_init - Initialize all team data * tm_gen - Generate dummy team names * legs_start_report - Generate starters report * ls_timer - print the current leg entry * ls_team - print next ( numeric ) leg entry * sort_legs - Qsort callback function * * programmer: David Purdie * * revision date by reason * 11-Oct-89 DDP leg-3 starttime. Now has an option to generate * a printed report of teams and times * * 21-May-90 MV now able to set start time and generate * a printed report for any leg * 00.0 27/01/95 DDP Tidies up the program and formatted the file * **************************************************************************/ #include "consts.h" #include "structs.h" #include "proto.h" #if defined(HI_TECH_C) || defined(__TURBOC__) #include #endif menu_table leg_menu[] = { { '1', "Set start time from category", leg_start }, { '2', "Clear all leg times", leg_ini }, { '3', "Reset team information", tm_init }, { '4', "Generate dummy team names", tm_gen }, { '5', "Set calculated leg start", tm_lgs }, { '6', "Set ordered incremental leg start", tm_lgs1 }, { '7', "Set staggered start time", tm_staggered }, { '8', "Set fixed start time", tm_fixedstart }, { '9', "Clear single leg start times", tm_clearleg }, { 'q', "Return to main menu", 0 }, { '\0' } }; /*======================================================================== * * Menu: Setup leg times * * Purpose: * This function is called to produce the menu that will * setup leg times * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void set_legs(void) { do_menu( "Leg time setup", "Select option", leg_menu ); } /*======================================================================== * * Set up the leg start times for leg * * Purpose: * This function is called to Set up the leg start times for leg * The start time is based on category information * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void tm_lgs1(void) { time_t delta; /* The time delta */ time_t starttime; int report_it = FALSE; /* Report the operation */ int clear_it = FALSE; t_legs *data; /* Address of table */ t_legs *dptr; /* Moving pointer */ int num_records; /* Number of records in array */ int i; cur( 0, 5 ); while( TRUE ) { leg = 0; d_field( 0, 5, "Enter leg to set start time :", D_NUMBER, 1, ( char * ) &leg, TRUE, M_UPDATE ); if( leg == 0 ) return; /* Null leg - just exit */ if( leg <= config.num_legs ) /* Valid leg number - Exit loop */ break; beep(); /* Make a noise and wait for valid number */ } cur( 0, 5 ); printf ( "Setting start times for all valid teams from %-d to %-d for leg %d\n", config.min_team, config.max_team, leg ); starttime = 0; do { d_time( 0, 6, "Enter the start time : ", &starttime, TRUE ); if( abort_flag ) return; if( starttime < 0 ) beep(); } while( starttime < 0 ); delta = 0; do { d_time( 0, 7, "Enter the delta time : ", &delta, TRUE ); if( abort_flag ) return; if( delta < 0 ) beep(); } while( delta < 0 ); report_it = getyes( "\nGenerate leg start report" ); if( abort_flag ) return; clear_it = getyes("Invalidate the leg start times" ); if( abort_flag ) return; /* ** Read existing data into memory */ data = ( t_legs * ) calloc( ( unsigned ) ( config.max_team - config.min_team + 2 ), sizeof( t_legs ) ); /* Fetch memory */ if( !data ) { printf( "\nNo memory for report\n" ); return; } /* * Extract the required data from the data base * Only save that information required for the operation * - The end time of the previous leg */ dptr = data; num_records = 0; for( i = config.min_team; i <= config.max_team; i++ ) { if( valid_field( i ) && g_record( i, &team_buf ) ) { dptr->numb = team_buf.numb; dptr->start = team_buf.leg[leg-1].end; dptr->flags = team_buf.flags; dptr++; num_records++; } } /* * Sort the data into some logical order */ qsort( ( char * ) data, num_records, sizeof( t_legs ), sort_legs ); /* ** Update the team information based on the start order ** Ignore validity flags as the data will have been sorted with ** these in mind. */ for( dptr = data, i = 0; i < num_records; i++, dptr++ ) { if( valid_field( dptr->numb ) ) { g_record( dptr->numb, &team_buf ); team_buf.leg[leg].start = starttime; starttime += delta; team_buf.leg[leg].manual = TRUE; set_times( &team_buf ); test_times( &team_buf, 0 ); put_team_record( dptr->numb, &team_buf ); } if( i % 10 == 0 ) { cur( 0, 8 ); printf( "Upto entry %d", i ); flush_out(); } } /* ** Release the data */ free( data ); if( report_it ) legs_start_report(9); if ( clear_it ) tm_clearleg_specified( leg, TRUE, 10 ); } /*======================================================================== * * Set up the leg start times for leg * * Purpose: * This function is called to Set up the leg start times for leg * The start time is based on current placing with: * A constant offset added ( ie: lunch) * A fixed increment * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void tm_lgs(void) { time_t delta; /* The time delta */ int report_it = FALSE; /* Report the operation */ int clear_it = FALSE; int line = 5; /* Current line */ cur( 0, line ); while( TRUE ) { leg = 0; d_field( 0, line, "Enter leg to set start time :", D_NUMBER, 1, ( char * ) &leg, TRUE, M_UPDATE ); if( leg == 0 ) return; /* Null leg - just exit */ if( leg <= config.num_legs ) /* Valid leg number - Exit loop */ break; beep(); /* Make a noise and wait for valid number */ } cur( 0, ++line ); printf ( "Setting start times for all valid teams from %-d to %-d for leg %d\n", config.min_team, config.max_team, leg ); delta = 0; line++; do { d_time( 0, line, "Enter the time difference : ", &delta, TRUE ); if( abort_flag ) return; if( delta < 0 ) beep(); } while( delta < 0 ); line++; report_it = getyes( "\nGenerate leg start report" ); if( abort_flag ) return; line++; clear_it = getyes("Invalidate the leg start times" ); if( abort_flag ) return; line++; team = config.min_team; /* Team we are working with */ while( team <= config.max_team ) { if( valid_field( team ) ) { g_record( team, &team_buf ); if( team_buf.flags.valid && team_buf.leg[leg - 1].end > 0 ) { team_buf.leg[leg].start = team_buf.leg[leg - 1].end + delta; team_buf.leg[leg].manual = TRUE; } else team_buf.leg[leg].start = ( time_t ) - 1; set_times( &team_buf ); test_times( &team_buf, 0 ); put_team_record( team, &team_buf ); } if( team % 10 == 0 ) { cur( 0, line ); printf( "Upto team %d", team ); flush_out(); } team++; } if( report_it ) legs_start_report(++line); if ( clear_it ) tm_clearleg_specified( leg, TRUE, ++line ); } /*======================================================================== * * Set up the leg start times * * Purpose: * This function is called to Set up the leg start times * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void leg_start(void) { team = config.min_team; /* Team we are working with */ cur( 0, 5 ); printf( "Setting start times for all valid teams from %-d to %-d \n", config.min_team, config.max_team ); if( !getyes( "Continue operation" ) ) return; while( team <= config.max_team ) { if( valid_field( team ) ) { ( void ) g_record( team, &team_buf ); if( team_buf.class > 0 && team_buf.class <= config.num_class ) team_buf.leg[0].start = config.team_class[team_buf.class - 1].start; else team_buf.leg[0].start = ( time_t ) - 1; team_buf.leg[1].manual = 0; team_buf.leg[1].start = team_buf.leg[0].start; team_buf.leg[0].l_place = 0; team_buf.leg[0].le_place = 0; team_buf.leg[0].lec_place = 0; team_buf.leg[0].lc_place = 0; team_buf.leg[0].manual = FALSE; set_times( &team_buf ); test_times( &team_buf, 0 ); put_team_record( team, &team_buf ); } if( team % 10 == 0 ) { cur( 0, 8 ); printf( "Upto team %d", team ); flush_out(); } team++; } } /*======================================================================== * * Set the start time for a specific leg * * Purpose: * This function is called to set the start time for a specific * leg to a specified and fixed time * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void tm_fixedstart(void) { time_t starttime; /* The start time */ int report_it = FALSE; /* Report the operation */ int clear_it = FALSE; int line = 5; /* Current line */ cur( 0, 5 ); while( TRUE ) { leg = 0; d_field( 0, line, "Enter leg to set start time :", D_NUMBER, 1, ( char * ) &leg, TRUE, M_UPDATE ); if( leg == 0 ) return; /* Null leg - just exit */ if( leg <= config.num_legs ) /* Valid leg number - Exit loop */ break; beep(); /* Make a noise and wait for valid number */ } line++; team = config.min_team; /* Team we are working with */ cur( 0, line++ ); printf ( "Setting start times for all valid teams from %-d to %-d for leg %d\n", config.min_team, config.max_team, leg ); starttime = 0; do { d_time( 0, line, "Enter the start time : ", &starttime, TRUE ); if( abort_flag ) return; if( starttime < 0 ) beep(); } while( starttime < 0 ); line++; report_it = getyes( "\nGenerate leg start report" ); if( abort_flag ) return; line++; clear_it = getyes("Invalidate the leg start times" ); if( abort_flag ) return; while( team <= config.max_team ) { if( valid_field( team ) ) { g_record( team, &team_buf ); if( team_buf.flags.valid ) { team_buf.leg[leg].start = starttime; team_buf.leg[leg].manual = TRUE; } else team_buf.leg[leg].start = ( time_t ) - 1; set_times( &team_buf ); test_times( &team_buf, 0 ); put_team_record( team, &team_buf ); } if( team % 10 == 0 ) { cur( 0, 8 ); printf( "Upto team %d", team ); flush_out(); } team++; } if( report_it ) legs_start_report(++line); if ( clear_it ) tm_clearleg_specified( leg, TRUE, ++line ); } /*======================================================================== * * Set a staggered start time for a specific leg * * Purpose: * This function is called to set the start time for a specific * leg to a specified and a staggered time * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void tm_staggered(void) { time_t starttime; /* The start time */ time_t delta; /* The stagger */ int report_it = FALSE; /* Report the operation */ int clear_it = FALSE; int line = 5; /* Current line */ cur( 0, line ); while( TRUE ) { leg = 0; d_field( 0, 5, "Enter leg to set start time :", D_NUMBER, 1, ( char * ) &leg, TRUE, M_UPDATE ); if( leg == 0 ) return; /* Null leg - just exit */ if( leg <= config.num_legs ) /* Valid leg number - Exit loop */ break; beep(); /* Make a noise and wait for valid number */ } line++; team = config.min_team; /* Team we are working with */ cur( 0, line++ ); printf ( "Setting staggered start times for all valid teams from %-d to %-d for leg %d\n", config.min_team, config.max_team, leg ); starttime = 0; do { d_time( 0, line, "Enter the start time : ", &starttime, TRUE ); if( abort_flag ) return; if( starttime < 0 ) beep(); } while( starttime < 0 ); line++; delta = 0; do { d_time( 0, line, "Enter the stagger time : ", &delta, TRUE ); if( abort_flag ) return; if( delta < 0 ) beep(); } while( delta < 0 ); line++; report_it = getyes( "\nGenerate leg start report" ); if( abort_flag ) return; line++; clear_it = getyes("Invalidate the leg start times" ); if( abort_flag ) return; while( team <= config.max_team ) { if( valid_field( team ) ) { g_record( team, &team_buf ); if( team_buf.flags.valid ) { team_buf.leg[leg].start = starttime; starttime += delta; team_buf.leg[leg].manual = TRUE; } else team_buf.leg[leg].start = ( time_t ) - 1; set_times( &team_buf ); test_times( &team_buf, 0 ); put_team_record( team, &team_buf ); } if( team % 10 == 0 ) { cur( 0, 9 ); printf( "Upto team %d", team ); flush_out(); } team++; } if( report_it ) legs_start_report(++line); if ( clear_it ) tm_clearleg_specified( leg, TRUE, ++line ); } /*======================================================================== * * Clear start times on a specific leg * * Purpose: * This function is called to clear start times on a specifc leg * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void tm_clearleg(void) { cur( 0, 5 ); while( TRUE ) { leg = 0; d_field( 0, 5, "Enter leg to clear start time :", D_NUMBER, 1, ( char * ) &leg, TRUE, M_UPDATE ); if( leg == 0 ) return; /* Null leg - just exit */ if( leg <= config.num_legs ) /* Valid leg number - Exit loop */ break; beep(); /* Make a noise and wait for valid number */ } cur( 0, 5 ); printf ( "Setting start times for all valid teams from %-d to %-d for leg %d\n", config.min_team, config.max_team, leg ); if( !getyes( "Continue operation" ) ) return; tm_clearleg_specified( leg, FALSE, 6 ); } /*======================================================================== * * Clear start times on a specific leg * * Purpose: * This function is called to clear start times on a specifc leg * * Parameters: * cleg - Leg to clear * manual - Force manual, else leave alone * line - Current display line number * * Returns: * Nothing * *========================================================================*/ void tm_clearleg_specified(int cleg, bool manual, int line) { /* ** Validate the users argument */ if( cleg == 0 ) return; /* Null leg - just exit */ if( cleg > config.num_legs ) /* Valid leg number - Exit loop */ return; leg = cleg; team = config.min_team; /* Team we are working with */ while( team <= config.max_team ) { if( valid_field( team ) ) { g_record( team, &team_buf ); team_buf.leg[leg].manual = manual; team_buf.leg[leg].start = ( time_t ) -1; set_times( &team_buf ); test_times( &team_buf, 0 ); put_team_record( team, &team_buf ); } if( team % 10 == 0 ) { cur( 0, line ); printf( "Upto team %d", team ); flush_out(); } team++; } } /*======================================================================== * * Initialize all stored times * * Purpose: * This function is called to Initialize all stored times * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void leg_ini(void) { int i; team = config.min_team; /* Team we are working with */ cur( 0, 5 ); printf( "\nInitializing ALL times for all valid teams from %-d to %-d\n", config.min_team, config.max_team ); if( !getyes( "Continue operation" ) ) return; while( team <= config.max_team ) { if( valid_field( team ) ) { ( void ) g_record( team, &team_buf ); for( i = 0; i <= MAX_LEGS; i++ ) { team_buf.leg[i].start = team_buf.leg[i].end = team_buf.leg[i].elapsed = ( time_t ) - 1; team_buf.leg[i].l_place = 0; team_buf.leg[i].le_place = 0; team_buf.leg[i].lec_place = 0; team_buf.leg[i].lc_place = 0; team_buf.leg[i].manual = FALSE; } if( team_buf.class > 0 && team_buf.class <= config.num_class ) team_buf.leg[0].start = config.team_class[team_buf.class - 1].start; else team_buf.leg[0].start = ( time_t ) - 1; team_buf.leg[1].start = team_buf.leg[0].start; team_buf.flags.disqualified = FALSE; team_buf.flags.non_equestrian = FALSE; put_team_record( team, &team_buf ); } if( team % 10 == 0 ) { cur( 0, 8 ); printf( "Upto team %d", team ); flush_out(); } team++; } } /*======================================================================== * * Initialize all team data * * Purpose: * This function is called to Initialize all team data * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void tm_init(void) { team = config.min_team; /* Team we are working with */ cur( 0, 5 ); printf ( "\nDelete ALL team information for all valid teams from %-d to %-d\n", config.min_team, config.max_team ); if( !getyes( "Continue operation" ) ) return; while( team <= config.max_team ) { if( valid_field( team ) ) { clr_team( team, &team_buf ); put_team_record( team, &team_buf ); } if( team % 10 == 0 ) { cur( 0, 8 ); printf( "Upto team %d", team ); flush_out(); } team++; } } /*======================================================================== * * Generate dummy team names * * Purpose: * This function is called to Generate dummy team names * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void tm_gen(void) { team = config.min_team; /* Team we are working with */ cur( 0, 5 ); printf( "Generate DUMMY team names for all valid teams from %-d to %-d\n", config.min_team, config.max_team ); if( !getyes( "Continue operation" ) ) return; while( team <= config.max_team ) { if( valid_field( team ) ) { ( void ) g_record( team, &team_buf ); team_buf.flags.valid = TRUE; sprintf( team_buf.name, "Team - %4.4d", team ); team_buf.class = 1; /* Set default class */ put_team_record( team, &team_buf ); } if( team % 10 == 0 ) { cur( 0, 8 ); printf( "Upto team %d", team ); flush_out(); } team++; } } /*======================================================================== * * Generate starters report * * Purpose: * This routine is used to generate a list of leg start times * This system can cope with a break at the start of leg * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void legs_start_report(int line) { int i; t_legs *data; /* Address of table */ t_legs *dptr; /* Moving pointer */ int last_team; int num_records = 0; /* Number of records in array */ char l_s[40]; /* Name of start time file */ cur( 0, line ); printf( "Generating Starters report for Leg-%d", leg ); data = ( t_legs * ) calloc( ( unsigned ) ( config.max_team - config.min_team + 2 ), sizeof( t_legs ) ); /* Fetch memory */ if( !data ) { printf( "\nNo memory for report\n" ); return; } /* * Extract the required data from the data base * Only save that information required for the operation */ dptr = data; for( i = config.min_team; i <= config.max_team; i++ ) /* Print team order data */ { if( valid_field( i ) && g_record( i, &team_buf ) ) { dptr->numb = team_buf.numb; dptr->start = team_buf.leg[leg].start; dptr->flags = team_buf.flags; dptr++; num_records++; } } /* * Sort the data into some logical order */ qsort( ( char * ) data, num_records, sizeof( t_legs ), sort_legs ); /* ** Now print the data on the printer ** - Generte the name of the printer file ** - Open the printer */ sprintf( l_s, "l_%d", leg ); if( !open_printer( "", l_s, 80, FALSE, "Starters Report" ) ) return; /* * Print out the header for the file */ print( "\nStarters report for leg:%d %-*s\n", leg, 18, config.leg_name[leg - 1] ); print( "Team order listing\n\n" ); print_underline (TRUE); print( "%-8s %-5s %-8s | %-5s %-8s", "Time", "Team", "DeltaT", "Team", "Time" ); print_underline (FALSE); print( "\n" ); last_team = 0; for( dptr = data, i = 0; i < num_records; i++ ) { ls_timer( dptr++, i ); print( " | " ); ls_team( &last_team, data ); print( "\n" ); } print( "\nTeams without marked times will be started when ALL marked teams\n" ); print( "have been started.\n" ); /* ** Release the resources ** - Printer ** - Memory */ close_printer(); free( data ); } /*======================================================================== * * print the current leg entry * * Purpose: * This function is a helper routine to print the current leg entry * in time : Team number order * * Parameters: * ptr Pointer to entry * num Entry index * * Returns: * Nothing * *========================================================================*/ void ls_timer( t_legs * ptr, int num ) { time_t time; time_t delta; if( num == 0 ) delta = ( time_t ) - 1; else delta = ptr[0].start - ptr[-1].start; time = ptr->start; if( ptr->flags.disqualified ) time = ( time_t ) - 1; print( "%-8s %-5d", time_fa( time, ptr->flags.disqualified ), ptr->numb ); print( " %-8s", time_fa( delta, TRUE ) ); } /*======================================================================== * * print next ( numeric ) leg entry * * Purpose: * This helper function is called to print next ( numeric ) leg entry * in Team # time order * * Parameters: * last Last one found * Used to relocate my self * data Start of data * * Returns: * Nothing * *========================================================================*/ void ls_team( int *last, t_legs * data ) { t_legs *min; time_t time; for( min = 0; data->numb; data++ ) { if( data->numb > *last && ( min == 0 || data->numb < min->numb ) ) min = data; } *last = min->numb; /* Save current team as done */ time = min->start; if( min->flags.disqualified ) time = ( time_t ) - 1; print( "%-5d %-8s", min->numb, time_fa( time, min->flags.disqualified ) ); } /*======================================================================== * * Qsort callback function * * Purpose: * This function is provided to Qsort() to sort the teams * * Parameters: * a - Leg entry to compare * b - Leg entry to compare * * * Returns: * -1 a < b * 0 a = b * 1 a > b * *========================================================================*/ int sort_legs( const void * aa, const void * bb ) { const t_legs * a = aa; const t_legs * b = bb; int a_bad; int b_bad; a_bad = a->flags.disqualified || a->start <= 0; b_bad = b->flags.disqualified || b->start <= 0; if( a_bad || b_bad ) /* Valid data has precedence */ { if( a_bad && b_bad ) return ( a->numb - b->numb ); else return ( a_bad ? 1 : -1 ); } if( a->start == b->start ) return ( a->numb - b->numb ); else { if( ( a->start > 0 ) && ( b->start > 0 ) ) return ( ( int ) ( a->start - b->start ) ); else return ( ( a->start > 0 ) ? -1 : 1 ); } } /********************************* EOF ***********************************/