Rev 46 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/************************************************************************** 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 );elsereturn ( 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 ***********************************/