/************************************************************************* * Copyright (C) 1995 Embedded Solutions * All rights reserved * * file: src\config.c * * purpose: Configuration module * This module will read in the configuration file and set up * all the configuration parameters * * functions * compact - Compact a string * conf_menu - Configuration Menu * configure - Read in the configuration file * d_class - Update the class information * d_cntry - Display / Update Country list * d_config - Configuration Update and Display * define_class - Update the class information * define_config - Alter the configuration file * define_country - Define a new entry in the county list * display_class - Display the class information * display_config - Display the marathon configuration * display_country - Display the current country list * f_comp_int - Qsort callback: Sort by team * r_config - Read in the configuration file * rd_config - Read in the configuration file * valid_field - Validate a team number * wt_config - Write out the configuration file * * programmer: David Purdie * * revision date by reason * 00.0 27/01/95 DDP Tidies up the program and formatted the file * **************************************************************************/ #include "consts.h" #include "structs.h" #include "proto.h" /* ** Local definitions */ char confile[20]; /* Name of the config file */ char datfile[20]; /* Name of the data file */ char filebase[20]; /* Event file name base */ MARA_CFG config; /* Working configuration */ MARA_CFG new; /* Play configuration */ t_class_summary class_summary; /* Class summary data */ menu_table cnf_menu[] = { {'1', "Display current configuration", display_config}, {'2', "Alter configuration", ( void ( * )( void ) ) define_config}, {'3', "Display category configuration", display_class}, {'4', "Alter category configuration", ( void ( * )( void ) ) define_class}, {'5', "Display country list", display_country}, {'6', "Alter country list", define_country}, {'7', "Display winners list", display_winners}, {'8', "Alter winners list", ( void ( * )( void ) ) define_winners}, {'q', "Return to main menu", 0}, {'\0'} }; /*======================================================================== * * Read in the configuration file * * Purpose: * This function is called to read in the configuration file * * Parameters: * c_name Name of the configuartion file * mode TRUE: Create the file * * Returns: * Returns TRUE if the system was configured ok * *========================================================================*/ bool configure( char *c_name, int mode ) { FILE * fcon; bool ok = FALSE; strncpy( filebase, c_name, 8 ); strcpy( confile, filebase ); strcat( confile, ".cnf" ); strcpy( datfile, filebase ); strcat( datfile, ".dat" ); fcon = fopen( confile, "rb" ); if ( fcon ) fclose( fcon ); if( mode ) { if( fcon ) { printf( "Configuration file already exists\n" ); ok = FALSE; } else { ok = define_config( ); /* Generate the configuration */ if( ok ) ok = define_class( ); } } else if( fcon ) ok = rd_config( ); /* read in the existing config */ else { ok = FALSE; printf( "Configuration file not found\n" ); } /* ** Post read calculations and fixups */ if( config.datafilename[0] ) { strcpy( datfile, config.datafilename ); strcat( datfile, ".dat" ); } config.nonequestrian_class = lookup_class( config.nonequestrian_class_abr, &config ); return ( ok ); } /*======================================================================== * * Configuration Menu * * Purpose: * This function is called to display the configuartion menu * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void conf_menu( void ) { do_menu( "Event configuration", "Select option", cnf_menu ); } /*======================================================================== * * Alter the configuration file * * Purpose: * This function is called to alter the configuration file * * Parameters: * None * * Returns: * TRUE - Configuration changed * FALSE - Configuration not changed * *========================================================================*/ bool define_config( void ) { int i, j; int error; bool changed = FALSE; int num_teams; /* ** Copy working configuration into a temp structure for ** use within the function */ new = config; do { error = 0; num_teams = 0; d_config( &new, M_UPDATE ); printf( "\n" ); compact( new.event_name ); /* Rip of leading white_space */ for( i = 0; i < MAX_LEGS; i++ ) compact( new.leg_name[i] ); compact( new.addendum ); compact( new.datafilename ); /* * Do all sorts of consistency tests on the data * Firstly - calculate the number of legs. Justify the data in the array */ new.num_legs = 0; for( i = 0; i < MAX_LEGS; i++ ) if( new.leg_name[i][0] ) new.num_legs++; for( i = new.num_legs; i < MAX_LEGS; i++ ) if( new.leg_name[i][0] ) { printf( "Configuration error: Missing leg\n" ); error++; } /* * Now do the team numbering stuff */ for( i = 0; i < MAX_TMS_SPLIT; i++ ) { if( new.t_def[i].start == 0 && new.t_def[i].end == 0 ) continue; if( new.t_def[i].start > new.t_def[i].end ) { printf ( "Team definition error : End greater than start. %d to %d\n", new.t_def[i].start, new.t_def[i].end ); error++; } for( j = 0; j < i; j++ ) { if( ( new.t_def[i].start >= new.t_def[j].start && new.t_def[i].start <= new.t_def[j].end ) || ( new.t_def[i].end >= new.t_def[j].start && new.t_def[i].end <= new.t_def[j].end ) ) { printf ( "Team definition error : Overlapping definition. %d to %d\n", new.t_def[i].start, new.t_def[i].end ); error++; } } } /* * Determine the number of team splits * There may be blank entries - these will be removed by sorting the array */ qsort( ( char * ) new.t_def, MAX_TMS_SPLIT, sizeof( *new.t_def ), f_comp_int ); for( new.num_teams = 0; new.num_teams < MAX_TMS_SPLIT; new.num_teams++ ) if( !new.t_def[new.num_teams].start ) break; new.min_team = new.t_def[0].start; new.max_team = new.t_def[new.num_teams - 1].end; /* ** Limit the number of entrants */ for( i = 0; i < MAX_TMS_SPLIT; i++ ) { if( new.t_def[i].start ) { num_teams += new.t_def[i].end - new.t_def[i].start + 1; } } #if defined(LIMIT_TEAMS) && (LIMIT_TEAMS > 0) if( num_teams > LIMIT_TEAMS ) { printf( "Maximum number of teams exceeded - reduce number of teams\n" ); error++; } #endif #if defined (HI_TECH_C) || defined (__TURBOC__) /* * Ensure that the number of teams allocated can fit within available * Memory space. Ie: Can we malloc the report data structures */ { long sz; sz = sizeof( ty_s_data ) > sizeof( ty_s_aux ) ? sizeof( ty_s_data ) : sizeof( ty_s_aux ); if( sz * ( new.max_team - new.min_team + 2 ) > ( 1024L * 64L ) ) { printf( "Too many teams: Reduce team spread.\n" ); error++; } } #endif /* ** Ensure the non-equestrian class and the equestrian leg are valid */ if( new.equestrian_leg ) { if( new.equestrian_leg > new.num_legs ) { printf( "Invalid non-equestrian leg number.\n" ); error++; } /* ** Ensure that the entered non-equestrian class name does exist */ new.nonequestrian_class = lookup_class( new.nonequestrian_class_abr, &new ); if( new.nonequestrian_class == 0 ) printf( "WARNING: Non-equestrian class not found\n" ); } abort_flag = FALSE; if( error ) { printf( "Configuration error - error must be corrected\n" ); printf( "Any key to continue " ); ( void ) getinp( ); continue; } else { printf( "Install configuration (Y)es, (D)iscard, (E)dit again :" ); switch ( getfnc( "*YDEA" ) ) { case 'Y': error = ( new.num_legs == 0 || new.num_teams == 0 ); if( error ) printf( "\nConfiguration not installed. No legs or teams defined\n" ); else { config = new; wt_config( ); /* Write out the data */ changed = TRUE; } break; case 'D': break; default: error = TRUE; break; } } } while( error ); return ( changed ); } /*======================================================================== * * Display the marathon configuration * * Purpose: * This function is called to Display the marathon configuration * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void display_config( void ) { d_config( &config, M_DISPLAY ); cur( 0, n_lines - 1 ); printf( "Any key to return to main menu :" ); getinp( ); } /*======================================================================== * * Display the class information * * Purpose: * This function is called to display the class information * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void display_class( void ) { d_class( &config, M_DISPLAY ); cur( 0, n_lines - 1 ); printf( "Any key to continue :" ); getinp( ); } /*======================================================================== * * Update the class information * * Purpose: * This function is called to update the class information * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ bool define_class( void ) { int error; int i; bool changed = FALSE; /* ** Copy working configuration into a temp structure for ** use within the function */ new = config; do { error = 0; d_class( &new, M_UPDATE ); printf( "\n" ); /* ** Now do the Class definitions */ for( i = 0; i < MAX_CLASS; i++ ) { compact( new.team_class[i].abr ); compact( new.team_class[i].full_name ); } for( i = 0; i < MAX_CLASS; i++ ) { if( ( new.team_class[i].abr[0] == '\0' ) != ( new.team_class[i].full_name[0] == '\0' ) ) { printf( "Configuration error. Class without description\n" ); error++; } if( new.team_class[i].abr[0] != '\0' && new.team_class[i].start < 0L ) { printf( "Configuration error. Bad start time on class\n" ); error++; } } new.num_class = 0; for( i = 0; i < MAX_CLASS; i++ ) if( new.team_class[i].full_name[0] ) new.num_class++; for( i = new.num_class; i < MAX_CLASS; i++ ) if( new.team_class[i].full_name[0] ) { printf( "Configuration error: Missing Class name. Gaps not allowed\n" ); error++; } if( new.num_class == 0 ) { printf( "Error: No categories defined\n" ); error++; } new.nonequestrian_class = lookup_class( new.nonequestrian_class_abr, &new ); if( new.equestrian_leg && new.nonequestrian_class == 0 ) printf( "WARNING: Non-equestrian class not found\n" ); abort_flag = FALSE; if( error ) { printf( "Any key to continue " ); getinp( ); } else { printf( "Install configuration (Y)es, (D)iscard, (E)dit again :" ); switch ( getfnc( "*YDEA" ) ) { case 'Y': config = new; wt_config( ); changed = TRUE; break; case 'D': break; default: error = TRUE; break; } } } while( error && ! abort_flag ); return ( changed ); } /*======================================================================== * * Update the class information * * Purpose: * This function is called to update the class information * Display the marathon classes from the system parameters. * * This routine can only be utilized after the screen system * has been initialized. * * Parameters: * operation Operation to perform * * Returns: * Nothing * *========================================================================*/ void d_class( MARA_CFG * config, int operation ) { int i, j, k; int maxitr; /* Max number of definitions during update */ int opr; abort_flag = FALSE; if( operation == M_UPDATE ) { opr = M_UPDATE; d_class( config, M_PREDISPLAY ); /* Force display before update */ } else { opr = M_DISPLAY; clearscreen( ); } i = 0; /* Set line 0 */ d_field( 0, i++, "Category definitions", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY ); i++; maxitr = ( operation == M_DISPLAY ) ? config->num_class : MAX_CLASS; for( j = 0, k = 0; j < maxitr; j++ ) { bool non_equestrian = FALSE; d_field( 0 + k, i, "Cat:", D_USTRING, 2, ( char * ) config->team_class[j].abr, TRUE, opr ); if( ( config->team_class[j].abr[0] == config->nonequestrian_class_abr[0] ) && ( config->team_class[j].abr[1] == config->nonequestrian_class_abr[1] ) ) { non_equestrian = TRUE; } d_field( 8 + k, i, ":", D_STRING, LEN_CLASS_NAME, config->team_class[j].full_name, TRUE, opr ); if( !non_equestrian ) d_field( LEN_CLASS_NAME + 10 + k, i, "Start:", D_TIME, 8, ( char * ) &config->team_class[j].start, TRUE, opr ); /* ** Step to next column or row */ k += 40; if( !( ( j + 1 ) % 2 ) ) { k = 0; i++; } } } /*======================================================================== * * Configuration Update and Display * * Purpose: * This function is called to Configuration Update and Display * * Parameters: * operation Operation to perform * * Returns: * Nothing * *========================================================================*/ void d_config( MARA_CFG * config, int operation ) { int i, j, k; int maxitr; /* Max number of definitions during update */ int opr; abort_flag = FALSE; if( operation == M_UPDATE ) { opr = M_UPDATE; d_config( config, M_PREDISPLAY ); /* Force display before update */ } else { opr = M_DISPLAY; clearscreen( ); } i = 0; /* Set line 0 */ d_field( 0, i++, "Marathon configuration", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY ); d_field( 0, ++i, "Name: ", D_STRING, MAX_EVENT_NAME, config->event_name, TRUE, opr ); /* * display the leg names */ i += 2; maxitr = ( operation == M_DISPLAY ) ? config->num_legs : MAX_LEGS; for( j = 1; j <= maxitr; j++, i++ ) { d_field( 0, i, "Leg ", D_NUMBER, 1, ( char * ) &j, TRUE, M_DISPLAY ); d_field( 6, i, ": ", D_STRING, MAX_LEG_NAME, config->leg_name[j - 1], TRUE, opr ); } abort_flag = FALSE; /* Trap aborts at the next field */ /* * Display the team break definitions */ i++; d_field( 0, i++, "Valid team numbers are in the following ranges", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY ); maxitr = ( operation == M_DISPLAY ) ? config->num_teams : MAX_TMS_SPLIT; for( k = 0, j = 0; j < maxitr; j++ ) { d_field( k + 0, i, "From ", D_NUMBER, 4, ( char * ) &config->t_def[j].start, TRUE, opr ); d_field( k + 9, i, " to ", D_NUMBER, 4, ( char * ) &config->t_def[j].end, TRUE, opr ); k += 20; if( !( ( j + 1 ) % 4 ) ) { k = 0; i++; } } /* * Name of legend config->addendum file */ abort_flag = FALSE; i++; d_field( 0, i++, "Legend addendum file :", D_STRING, ( int ) sizeof( config->addendum ) - 1, ( char * ) config->addendum, TRUE, opr ); /* * Name of the alternate data file */ d_field( 0, i++, "Data filename :", D_STRING, ( int ) sizeof( config->datafilename ) - 1, ( char * ) config->datafilename, TRUE, opr ); /* ** Non-equestrian configuration information */ abort_flag = FALSE; i++; d_field( 0, i++, "Equestrian Leg :", D_NUMBER, 1, ( char * ) &config->equestrian_leg, TRUE, opr ); d_field( 0, i++, "Non-Equestrian Category :", D_USTRING, ( int ) sizeof( config->nonequestrian_class_abr ) - 1, ( char * ) config->nonequestrian_class_abr, TRUE, opr ); /* ** Print control */ abort_flag = FALSE; i++; d_field( 0, i, "Lines Per Page :", D_NUMBER, 3, ( char * ) &config->lines_per_page, TRUE, opr ); d_field( 30, i++, "Perf Skip :", D_NUMBER, 1, ( char * ) &config->perf_skip, TRUE, opr ); } /*======================================================================== * * Display the current country list * * Purpose: * This function is called to Display the current country list * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void display_country( void ) { d_cntry( &config, M_DISPLAY ); cur( 0, n_lines - 1 ); printf( "Any key to return to main menu :" ); ( void ) getinp( ); } /*======================================================================== * * Define a new entry in the county list * * Purpose: * This function is called to Define a new entry in the county list * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void define_country( void ) { int error; ty_t_country *ptr; int i; /* ** Copy working configuration into a temp structure for ** use within the function */ new = config; do { error = 0; new.num_countries = 0; /* * Get the operator to update the screen */ d_cntry( &new, M_UPDATE ); /* Update the country data */ printf( "\n" ); /* * Now check the data that has been entered. */ ptr = new.country_name; for( i = 0; i < MAX_COUNTRY; i++, ptr++ ) { compact( ptr->abr ); compact( ptr->full_name ); if( ( ptr->abr[0] == '\0' ) != ( ptr->full_name[0] == '\0' ) ) { error++; printf( "Missing field\n" ); } if( ptr->abr[0] ) new.num_countries++; } if( error ) { printf( "Configuration error - error must be corrected\n" ); printf( "Any key to continue " ); ( void ) getinp( ); } else { printf( "Install configuration (Y)es, (D)iscard, (E)dit again :" ); switch ( getfnc( "*YDEA" ) ) { case 'Y': config = new; wt_config( ); /* Write out the data */ break; case 'D': break; default: error = TRUE; break; } } } while( error ); return; } /*======================================================================== * * Display / Update Country list * * Purpose: * This function is called to Display or Update Country list * * Parameters: * operation Operation to perform * * Returns: * Nothing * *========================================================================*/ void d_cntry( MARA_CFG * config, int operation ) { int i, j, k; int opr; abort_flag = FALSE; if( operation == M_UPDATE ) { opr = M_UPDATE; d_cntry( config, M_PREDISPLAY ); /* Force display before update */ } else { opr = M_DISPLAY; clearscreen( ); } i = 0; /* Set line 0 */ d_field( 0, i++, "Country classifications", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY ); /* * Display the country names */ i++; for( j = 0, k = 0; j < MAX_COUNTRY; j++ ) { d_field( 0 + k, i, "Country: ", D_STRING, 4, ( char * ) config->country_name[j].abr, TRUE, opr ); d_field( 13 + k, i, ": ", D_STRING, LEN_CNTRY_NAME, config->country_name[j].full_name, TRUE, opr ); k += 40; if( !( ( j + 1 ) % 2 ) ) { k = 0; i++; } } } /*======================================================================== * * Display the Winners List * * Purpose: * This function is called to Display the current winners list * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void display_winners( void ) { calc_class_summary( & class_summary ); d_winners( &config, M_DISPLAY ); cur( 0, n_lines - 1 ); printf( "Any key to return to main menu :" ); ( void ) getinp( ); } /*======================================================================== * * Update the winners information * * Purpose: * This function is called to update the winners information * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ bool define_winners( void ) { int error; int i; bool changed = FALSE; /* ** Update the class summary info to give the user a hint */ calc_class_summary( & class_summary ); /* ** Copy working configuration into a temp structure for ** use within the function */ new = config; /* ** Edit and sanity test the cnfig data until the user is happy ** with it - or is ready to discard it. */ do { error = 0; d_winners ( &new, M_UPDATE ); printf( "\n" ); /* ** Sanity test of the data */ for( i = 0; i < MAX_CLASS; i++ ) { if( new.team_class[i].abr[0] != '\0' && new.class_winners[i] == 0 ) { printf( " Warning: Class without winners: %s\n", new.team_class[i].abr ); } if ( new.class_winners[i] > class_summary.class[i+1].total ) { printf( " Warning: Num winners greater than those in class: %s\n", new.team_class[i].abr ); } } new.num_fame = 0; for( i = 0; i < MAX_FAME; i++ ) if( new.hall_fame[i][0] ) new.num_fame++; for( i = new.num_fame; i < MAX_FAME; i++ ) if( new.hall_fame[i][0] ) { printf( "Configuration error: Missing Fame name. Gaps not allowed\n" ); error++; break; } abort_flag = FALSE; if( error ) { printf( "Any key to continue " ); getinp( ); } else { printf( "Install configuration (Y)es, (D)iscard, (E)dit again :" ); switch ( getfnc( "*YDEA" ) ) { case 'Y': config = new; wt_config( ); changed = TRUE; break; case 'D': break; default: error = TRUE; break; } } } while( error && ! abort_flag ); return ( changed ); } /*======================================================================== * * Display / Update winners list * * Purpose: * This function is called to Display or Update winners list * * Parameters: * operation Operation to perform * * Returns: * Nothing * *========================================================================*/ void d_winners( MARA_CFG * config, int operation ) { int i, j, k; int maxitr; /* Max number of definitions during update */ int opr; abort_flag = FALSE; if( operation == M_UPDATE ) { opr = M_UPDATE; d_winners( config, M_PREDISPLAY ); /* Force display before update */ } else { opr = M_DISPLAY; clearscreen( ); } i = 0; /* Set line 0 */ d_field( 0, i++, "Winner definitions", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY ); i++; maxitr = config->num_class; for( j = 0, k = 0; j < maxitr; j++ ) { d_field( 0 + k, i, "Cat:", D_USTRING, 2, ( char * ) config->team_class[j].abr, TRUE, M_DISPLAY ); d_field( 7 + k, i, ":", D_STRING, LEN_CLASS_NAME, config->team_class[j].full_name, TRUE, M_DISPLAY ); d_field( LEN_CLASS_NAME + 9 + k, i, "Num:", D_NUMBER, 3, ( char * ) &class_summary.class[j+1].total, TRUE, M_DISPLAY ); d_field( LEN_CLASS_NAME + 9 + 7 + k, i, "Win:", D_NUMBER, 3, ( char * ) &config->class_winners[j], TRUE, opr ); /* ** Step to next column or row */ k += 40; if( !( ( j + 1 ) % 2 ) ) { k = 0; i++; } } abort_flag = FALSE; i += 2; d_field( 0, i++, "Hall of Fame", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY ); for( j = 0, k = 0; j < MAX_FAME; j++ ) { d_field( k, i, "Name : ", D_STRING, MAX_PERSON_NAME, &config->hall_fame[j], TRUE, opr ); k += 40; if( !( ( j + 1 ) % 2 ) ) { k = 0; i++; } } } /*======================================================================== * * Read in the configuration file * * Purpose: * This function is called to read in the configuration file * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ bool rd_config( void ) { FILE *fcon; int ok; fcon = fopen( confile, "rb" ); if( ! fcon ) { printf( "Configuration file %s not found\n", confile ); return ( FALSE ); } ok = r_config( fcon ); fclose( fcon ); return ( ok ); } /*======================================================================== * * Read in the configuration file * * Purpose: * This function is called to read in the configuration file * NOTE: Must be maintained with the Writer function * * Parameters: * fcon File number of the config file * * Returns: * FALSE if an error is encountered * *========================================================================*/ bool r_config( FILE *fcon ) { int len; /* Length of data read */ /* * Event name */ printf( "Reading: Event Name\n" ); len = fread( config.event_name, sizeof( config.event_name ), 1 , fcon ); if( len != 1 ) return ( FALSE ); /* * Leg names */ printf( "Reading: Leg Names\n" ); len = fread( config.leg_name, sizeof( config.leg_name ), 1 , fcon ); if( len != 1 ) return ( FALSE ); /* * Team definitions */ printf( "Reading: Team Defs\n" ); len = fread( config.t_def, sizeof( config.t_def ), 1 , fcon ); if( len != 1 ) return ( FALSE ); /* * Number of legs */ printf( "Reading: Leg Nums\n" ); len = fread( &config.num_legs, sizeof( config.num_legs ), 1 , fcon ); if( len != 1) return ( FALSE ); /* * Number of team splits */ printf( "Reading: Team Splits\n" ); len = fread( &config.num_teams, sizeof( config.num_teams ), 1 , fcon ); if( len != 1 ) return ( FALSE ); config.min_team = config.t_def[0].start; config.max_team = config.t_def[config.num_teams - 1].end; /* * Class information */ printf( "Reading: Class Data\n" ); len = fread( config.team_class, sizeof( config.team_class ), 1 , fcon ); if( len != 1 ) return ( FALSE ); len = fread( &config.num_class, sizeof( config.num_class ), 1 , fcon ); if( len != 1 ) return ( FALSE ); /* * Country list */ printf( "Reading: Country Data, Name\n" ); len = fread( config.country_name, sizeof( config.country_name ), 1 , fcon ); if( len != 1 ) return ( FALSE ); printf( "Reading: Country Data, Number\n" ); len = fread( &config.num_countries, sizeof( config.num_countries ), 1 , fcon ); if( len != 1 ) return ( FALSE ); /* * Addendum file */ printf( "Reading: Addendum File\n" ); len = fread( config.addendum, sizeof( config.addendum ), 1 , fcon ); if( len != 1 ) return ( feof( fcon ) ); /* * Name of the data file */ printf( "Reading: Name of data file\n" ); len = fread( config.datafilename, sizeof( config.datafilename ) , 1 , fcon ); if( len != 1 ) return ( feof( fcon ) ); /* ** Non-equestrian configuration information */ printf( "Reading: NonEquest\n" ); len = fread( config.nonequestrian_class_abr, sizeof( config.nonequestrian_class_abr ), 1 , fcon ); if( len != 1 ) return ( feof( fcon ) ); printf( "Reading: NonEquest-2\n" ); len = fread( &config.equestrian_leg, sizeof( config.equestrian_leg ), 1 , fcon ); if( len != 1 ) return ( FALSE ); /* ** .txt file output control. Lines per page and perf-skipping */ printf( "Reading: Output Control\n" ); len = fread( &config.lines_per_page, sizeof( config.lines_per_page ), 1 , fcon ); if( len != 1 ) return ( feof( fcon ) ); printf( "Reading: Output Control-2\n" ); len = fread( &config.perf_skip, sizeof( config.perf_skip ), 1 , fcon ); if( len != 1 ) return ( FALSE ); printf( "Reading: Winners Info\n" ); len = fread( &config.class_winners, sizeof( config.class_winners ), 1 , fcon ); if( len != 1 ) return ( FALSE ); printf( "Reading: Hall of Fame Info\n" ); len = fread( &config.hall_fame, sizeof( config.hall_fame ), 1 , fcon ); if( len != 1 ) return ( FALSE ); printf( "Reading: Hall of Fame Numbers\n" ); len = fread( &config.num_fame, sizeof( config.num_fame ), 1 , fcon ); if( len != 1 ) return ( feof( fcon ) ); return ( TRUE ); } /*======================================================================== * * Write out the configuration file * * Purpose: * This function is called to write the configuration file * NOTE: Must be maintained with the Reader function * * Parameters: * None * * Returns: * FALSE : Error encountered * *========================================================================*/ bool wt_config( void ) { FILE *fcon; /* ** Open as a binary file */ fcon = fopen( confile, "wb" ); if( !fcon ) return ( FALSE ); /* ** Write out multiple structures ** Event name ** Leg names ** Team definitions ** Number of legs ** Number fo team splits ** Class information ** Number of defined classes ** Country list ** Number of defined countries ** Legend config.addendum file name ** Data file name */ fwrite( config.event_name, sizeof( config.event_name ), 1, fcon ); fwrite( config.leg_name, sizeof( config.leg_name ), 1, fcon ); fwrite( config.t_def, sizeof( config.t_def ), 1, fcon ); fwrite( &config.num_legs, sizeof( config.num_legs ), 1, fcon ); fwrite( &config.num_teams, sizeof( config.num_teams ), 1, fcon ); fwrite( config.team_class, sizeof( config.team_class ), 1, fcon ); fwrite( &config.num_class, sizeof( config.num_class ), 1, fcon ); fwrite( config.country_name, sizeof( config.country_name ), 1, fcon ); fwrite( &config.num_countries, sizeof( config.num_countries ), 1, fcon ); fwrite( config.addendum, sizeof( config.addendum ), 1, fcon ); fwrite( config.datafilename, sizeof( config.datafilename ), 1, fcon ); fwrite( config.nonequestrian_class_abr, sizeof( config.nonequestrian_class_abr ), 1, fcon ); fwrite( &config.equestrian_leg, sizeof( config.equestrian_leg ), 1, fcon ); fwrite( &config.lines_per_page, sizeof( config.lines_per_page ), 1, fcon ); fwrite( &config.perf_skip, sizeof( config.perf_skip ), 1, fcon ); fwrite( &config.class_winners, sizeof( config.class_winners ), 1, fcon ); fwrite( &config.hall_fame, sizeof( config.hall_fame ), 1, fcon ); fwrite( &config.num_fame, sizeof( config.num_fame ), 1, fcon ); fclose( fcon ); return ( TRUE ); } /*======================================================================== * * Qsort callback: Sort by team * * Purpose: * Function used by the team definition sort operation * It will compare two entries of the team def structure and return an * integer for gt eq lt conditions. * Note : If the start is 0 the team entry does exist and is placed at the * end of the sorted list. * * Parameters: * a comparision entry * b comparision entry * * Returns: * gt, eq, lt as required * *========================================================================*/ int f_comp_int( const void *aa, const void *bb ) { const ty_t_def *a = aa; const ty_t_def *b = bb; if( a->start == 0 ) return ( 1 ); else if( b->start == 0 ) return ( -1 ); else return ( a->start - b->start ); } /*======================================================================== * * Compact a string * * Purpose: * This function is called remove leading and trailing spaces from * a string. Treats other non-printing characters as leading * spaces. This solves a problem when importing data from a * Microsoft CSV file with empty fields. * * Parameters: * str Address of the string to compact * * Returns: * Nothing * *========================================================================*/ void compact( char *str ) { char *ptr; ptr = str; while( *str && ( isspace( *str ) || !isprint( *str ) ) ) str++; strcpy( ptr, str ); } /*======================================================================== * * Validate a team number * * Purpose: * This function is called to validate a team number * * Parameters: * x Number to validate * * Returns: * TRUE : Valid * FALSE : Not valid * *========================================================================*/ bool valid_field( int x ) { int i; for( i = 0; i < config.num_teams; i++ ) { if( x <= config.t_def[i].end && x >= config.t_def[i].start ) return ( TRUE ); if( x < config.t_def[i].start ) break; /* Because the list is sorted */ } return ( FALSE ); } /*======================================================================== * * Get a class descriptor from existing text * * Purpose: * This function is called to Get a class descriptor * * Parameters: * text - User text to examine * config - configuration dtaa to use * * Returns: * An integer which is the index into the config.team_class array * The integer is in the range 1 .. num_class * A value fo zero indicates the text was not found. * *========================================================================*/ int lookup_class( char *text, MARA_CFG * config_ptr ) { int i; if( config_ptr == NULL ) config_ptr = &config; /* * Attempt to locate the entered class in the list of defined classes */ for( i = 0; i < config_ptr->num_class; i++ ) { if( toupper(text[0]) == toupper(config_ptr->team_class[i].abr[0]) && toupper(text[1]) == toupper(config_ptr->team_class[i].abr[1]) ) return ( ++i ); } return ( 0 ); } /********************************* EOF ***********************************/