Subversion Repositories svn1-original

Rev

Rev 1 | 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 );
    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 ***********************************/