Subversion Repositories svn1-original

Rev

Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 root 1
/*************************************************************************
2
*           Copyright (C) 1995 Embedded Solutions
3
*                       All rights reserved
4
*
5
* file:     src\config.c
6
*
7
* purpose:  Configuration module
8
*           This module will read in the configuration file and set up
9
*           all the configuration parameters
10
*
11
* functions
12
*       compact                 - Compact a string
13
*       conf_menu               - Configuration Menu
14
*       configure               - Read in the configuration file
15
*       d_class                 - Update the class information
16
*       d_cntry                 - Display / Update Country list
17
*       d_config                - Configuration Update and Display
18
*       define_class            - Update the class information
19
*       define_config           - Alter the configuration file
20
*       define_country          - Define a new entry in the county list
21
*       display_class           - Display the class information
22
*       display_config          - Display the marathon configuration
23
*       display_country         - Display the current country list
24
*       f_comp_int              - Qsort callback: Sort by team
25
*       r_config                - Read in the configuration file
26
*       rd_config               - Read in the configuration file
27
*       valid_field             - Validate a team number
28
*       wt_config               - Write out the configuration file
29
*
30
* programmer: David Purdie
31
*
32
* revision  date        by      reason
33
*   00.0    27/01/95    DDP     Tidies up the program and formatted the file
34
*
35
**************************************************************************/
36
 
37
#include    "consts.h"
38
#include    "structs.h"
39
#include    "proto.h"
40
 
41
/*
42
**  Local definitions
43
*/
44
char        confile[20];                         /* Name of the config file */
45
char        datfile[20];                         /* Name of the data file */
46
char        filebase[20];                        /* Event file name base */
47
 
48
MARA_CFG    config;                              /* Working configuration */
49
MARA_CFG    new;                                 /* Play configuration */
50
 
51
t_class_summary class_summary;                   /* Class summary data */
52
 
53
menu_table  cnf_menu[] = {
54
    {'1', "Display current configuration", display_config},
55
    {'2', "Alter configuration", ( void ( * )( void ) ) define_config},
56
    {'3', "Display category configuration", display_class},
57
    {'4', "Alter category configuration", ( void ( * )( void ) ) define_class},
58
    {'5', "Display country list", display_country},
59
    {'6', "Alter country list", define_country},
60
    {'7', "Display winners list", display_winners},
61
    {'8', "Alter winners list",  ( void ( * )( void ) ) define_winners},
62
    {'q', "Return to main menu", 0},
63
    {'\0'}
64
};
65
 
66
/*========================================================================
67
 *
68
 *  Read in the configuration file
69
 *
70
 *  Purpose:
71
 *      This function is called to read in the configuration file
72
 *
73
 *  Parameters:
74
 *      c_name      Name of the configuartion file
75
 *      mode        TRUE: Create the file
76
 *
77
 *  Returns:
78
 *      Returns TRUE if the system was configured ok
79
 *
80
 *========================================================================*/
81
 
82
bool configure( char *c_name, int mode )
83
{
84
 
85
    FILE        * fcon;
86
    bool        ok = FALSE;
87
 
88
    strncpy( filebase, c_name, 8 );
89
    strcpy( confile, filebase );
90
    strcat( confile, ".cnf" );
91
    strcpy( datfile, filebase );
92
    strcat( datfile, ".dat" );
93
 
94
    fcon = fopen( confile, "rb" );
95
    if ( fcon )
96
        fclose( fcon );
97
 
98
    if( mode )
99
    {
100
        if( fcon )
101
        {
102
            printf( "Configuration file already exists\n" );
103
            ok = FALSE;
104
        }
105
        else
106
        {
107
            ok = define_config(  );              /* Generate the configuration */
108
            if( ok )
109
                ok = define_class(  );
110
        }
111
    }
112
    else if( fcon )
113
        ok = rd_config(  );                      /* read in the existing config */
114
    else
115
    {
116
        ok = FALSE;
117
        printf( "Configuration file not found\n" );
118
    }
119
 
120
    /*
121
     **  Post read calculations and fixups
122
     */
123
    if( config.datafilename[0] )
124
    {
125
        strcpy( datfile, config.datafilename );
126
        strcat( datfile, ".dat" );
127
    }
128
    config.nonequestrian_class = lookup_class( config.nonequestrian_class_abr, &config );
129
    return ( ok );
130
}
131
 
132
/*========================================================================
133
 *
134
 *  Configuration Menu
135
 *
136
 *  Purpose:
137
 *      This function is called to display the configuartion menu
138
 *
139
 *  Parameters:
140
 *      None
141
 *
142
 *  Returns:
143
 *      Nothing
144
 *
145
 *========================================================================*/
146
 
147
void conf_menu( void )
148
{
149
    do_menu( "Event configuration", "Select option", cnf_menu );
150
}
151
 
152
/*========================================================================
153
 *
154
 *  Alter the configuration file
155
 *
156
 *  Purpose:
157
 *      This function is called to alter the configuration file
158
 *
159
 *  Parameters:
160
 *      None
161
 *
162
 *  Returns:
163
 *      TRUE    - Configuration changed
164
 *      FALSE   - Configuration not changed
165
 *
166
 *========================================================================*/
167
 
168
bool define_config( void )
169
{
170
    int         i, j;
171
    int         error;
172
    bool        changed = FALSE;
173
    int         num_teams;
174
 
175
    /*
176
     **  Copy working configuration into a temp structure for
177
     **  use within the function
178
     */
179
    new = config;
180
 
181
    do
182
    {
183
        error = 0;
184
        num_teams = 0;
185
        d_config( &new, M_UPDATE );
186
        printf( "\n" );
187
 
188
        compact( new.event_name );               /* Rip of leading white_space */
189
        for( i = 0; i < MAX_LEGS; i++ )
190
            compact( new.leg_name[i] );
191
        compact( new.addendum );
192
        compact( new.datafilename );
193
 
194
        /*
195
         * Do all sorts of consistency tests on the data 
196
         * Firstly - calculate the number of legs. Justify the data in the array
197
         */
198
 
199
        new.num_legs = 0;
200
        for( i = 0; i < MAX_LEGS; i++ )
201
            if( new.leg_name[i][0] )
202
                new.num_legs++;
203
        for( i = new.num_legs; i < MAX_LEGS; i++ )
204
            if( new.leg_name[i][0] )
205
            {
206
                printf( "Configuration error: Missing leg\n" );
207
                error++;
208
            }
209
 
210
 
211
        /*
212
         * Now do the team numbering stuff 
213
         */
214
 
215
        for( i = 0; i < MAX_TMS_SPLIT; i++ )
216
        {
217
            if( new.t_def[i].start == 0 && new.t_def[i].end == 0 )
218
                continue;
219
            if( new.t_def[i].start > new.t_def[i].end )
220
            {
221
                printf
222
                    ( "Team definition error : End greater than start. %d to %d\n",
223
                      new.t_def[i].start, new.t_def[i].end );
224
                error++;
225
            }
226
            for( j = 0; j < i; j++ )
227
            {
228
                if( ( new.t_def[i].start >= new.t_def[j].start
229
                      && new.t_def[i].start <= new.t_def[j].end )
230
                    || ( new.t_def[i].end >= new.t_def[j].start
231
                         && new.t_def[i].end <= new.t_def[j].end ) )
232
                {
233
                    printf
234
                        ( "Team definition error : Overlapping definition. %d to %d\n",
235
                          new.t_def[i].start, new.t_def[i].end );
236
                    error++;
237
                }
238
            }
239
        }
240
 
241
        /*
242
         * Determine the number of team splits
243
         * There may be blank entries - these will be removed by sorting the array
244
         */
245
        qsort( ( char * ) new.t_def, MAX_TMS_SPLIT, sizeof( *new.t_def ), f_comp_int );
246
        for( new.num_teams = 0; new.num_teams < MAX_TMS_SPLIT; new.num_teams++ )
247
            if( !new.t_def[new.num_teams].start )
248
                break;
249
 
250
        new.min_team = new.t_def[0].start;
251
        new.max_team = new.t_def[new.num_teams - 1].end;
252
 
253
        /*
254
         **  Limit the number of entrants
255
         */
256
        for( i = 0; i < MAX_TMS_SPLIT; i++ )
257
        {
258
            if( new.t_def[i].start )
259
            {
260
                num_teams += new.t_def[i].end - new.t_def[i].start + 1;
261
            }
262
        }
263
#if defined(LIMIT_TEAMS) && (LIMIT_TEAMS > 0)
264
        if( num_teams > LIMIT_TEAMS )
265
        {
266
            printf( "Maximum number of teams exceeded - reduce number of teams\n" );
267
            error++;
268
        }
269
#endif
270
 
271
#if defined (HI_TECH_C) || defined (__TURBOC__)
272
 
273
        /*
274
         * Ensure that the number of teams allocated can fit within available
275
         * Memory space. Ie: Can we malloc the report data structures
276
         */
277
        {
278
            long        sz;
279
 
280
            sz = sizeof( ty_s_data ) > sizeof( ty_s_aux ) ?
281
                sizeof( ty_s_data ) : sizeof( ty_s_aux );
282
            if( sz * ( new.max_team - new.min_team + 2 ) > ( 1024L * 64L ) )
283
            {
284
                printf( "Too many teams: Reduce team spread.\n" );
285
                error++;
286
            }
287
        }
288
#endif
289
 
290
        /*
291
         **  Ensure the non-equestrian class and the equestrian leg are valid
292
         */
293
        if( new.equestrian_leg )
294
        {
295
            if( new.equestrian_leg > new.num_legs )
296
            {
297
                printf( "Invalid non-equestrian leg number.\n" );
298
                error++;
299
            }
300
 
301
            /*
302
             **  Ensure that the entered non-equestrian class name does exist
303
             */
304
            new.nonequestrian_class = lookup_class( new.nonequestrian_class_abr, &new );
305
            if( new.nonequestrian_class == 0 )
306
                printf( "WARNING: Non-equestrian class not found\n" );
307
        }
308
 
309
        abort_flag = FALSE;
310
        if( error )
311
        {
312
            printf( "Configuration error - error must be corrected\n" );
313
            printf( "Any key to continue " );
314
            ( void ) getinp(  );
315
            continue;
316
        }
317
        else
318
        {
319
            printf( "Install configuration (Y)es, (D)iscard, (E)dit again :" );
320
            switch ( getfnc( "*YDEA" ) )
321
            {
322
            case 'Y':
323
                error = ( new.num_legs == 0 || new.num_teams == 0 );
324
                if( error )
325
                    printf( "\nConfiguration not installed. No legs or teams defined\n" );
326
                else
327
                {
328
                    config = new;
329
                    wt_config(  );               /* Write out the data */
330
                    changed = TRUE;
331
                }
332
                break;
333
 
334
            case 'D':
335
                break;
336
 
337
            default:
338
                error = TRUE;
339
                break;
340
            }
341
        }
342
    }
343
    while( error );
344
 
345
    return ( changed );
346
}
347
 
348
 
349
/*========================================================================
350
 *
351
 *  Display the marathon configuration
352
 *
353
 *  Purpose:
354
 *      This function is called to Display the marathon configuration
355
 *
356
 *  Parameters:
357
 *      None
358
 *
359
 *  Returns:
360
 *      Nothing
361
 *
362
 *========================================================================*/
363
 
364
void display_config( void )
365
{
366
    d_config( &config, M_DISPLAY );
367
 
368
    cur( 0, n_lines - 1 );
369
    printf( "Any key to return to main menu :" );
370
    getinp(  );
371
}
372
 
373
 
374
/*========================================================================
375
 *
376
 *  Display the class information
377
 *
378
 *  Purpose:
379
 *      This function is called to display the class information
380
 *
381
 *  Parameters:
382
 *      None
383
 *
384
 *  Returns:
385
 *      Nothing
386
 *
387
 *========================================================================*/
388
 
389
void display_class( void )
390
{
391
    d_class( &config, M_DISPLAY );
392
 
393
    cur( 0, n_lines - 1 );
394
    printf( "Any key to continue :" );
395
    getinp(  );
396
}
397
 
398
/*========================================================================
399
 *
400
 *  Update the class information
401
 *
402
 *  Purpose:
403
 *      This function is called to update the class information
404
 *
405
 *  Parameters:
406
 *      None
407
 *
408
 *  Returns:
409
 *      Nothing
410
 *
411
 *========================================================================*/
412
 
413
bool define_class( void )
414
{
415
    int         error;
416
    int         i;
417
    bool        changed = FALSE;
418
 
419
    /*
420
     **  Copy working configuration into a temp structure for
421
     **  use within the function
422
     */
423
    new = config;
424
 
425
    do
426
    {
427
        error = 0;
428
        d_class( &new, M_UPDATE );
429
        printf( "\n" );
430
 
431
        /*
432
         **  Now do the Class definitions
433
         */
434
        for( i = 0; i < MAX_CLASS; i++ )
435
        {
436
            compact( new.team_class[i].abr );
437
            compact( new.team_class[i].full_name );
438
        }
439
 
440
        for( i = 0; i < MAX_CLASS; i++ )
441
        {
442
            if( ( new.team_class[i].abr[0] == '\0' ) != ( new.team_class[i].full_name[0] == '\0' ) )
443
            {
444
                printf( "Configuration error. Class without description\n" );
445
                error++;
446
            }
447
            if( new.team_class[i].abr[0] != '\0' && new.team_class[i].start < 0L )
448
            {
449
                printf( "Configuration error. Bad start time on class\n" );
450
                error++;
451
            }
452
        }
453
 
454
        new.num_class = 0;
455
        for( i = 0; i < MAX_CLASS; i++ )
456
            if( new.team_class[i].full_name[0] )
457
                new.num_class++;
458
 
459
        for( i = new.num_class; i < MAX_CLASS; i++ )
460
            if( new.team_class[i].full_name[0] )
461
            {
462
                printf( "Configuration error: Missing Class name. Gaps not allowed\n" );
463
                error++;
464
            }
465
 
466
        if( new.num_class == 0 )
467
        {
468
            printf( "Error: No categories defined\n" );
469
            error++;
470
        }
471
 
472
        new.nonequestrian_class = lookup_class( new.nonequestrian_class_abr, &new );
473
        if( new.equestrian_leg && new.nonequestrian_class == 0 )
474
            printf( "WARNING: Non-equestrian class not found\n" );
475
 
476
        abort_flag = FALSE;
477
        if( error )
478
        {
479
            printf( "Any key to continue " );
480
            getinp(  );
481
        }
482
        else
483
        {
484
            printf( "Install configuration (Y)es, (D)iscard, (E)dit again :" );
485
            switch ( getfnc( "*YDEA" ) )
486
            {
487
            case 'Y':
488
                config = new;
489
                wt_config(  );
490
                changed = TRUE;
491
                break;
492
 
493
            case 'D':
494
                break;
495
 
496
            default:
497
                error = TRUE;
498
                break;
499
            }
500
        }
501
    } while( error && ! abort_flag );
502
    return ( changed );
503
}
504
 
505
/*========================================================================
506
 *
507
 *  Update the class information
508
 *
509
 *  Purpose:
510
 *      This function is called to update the class information
511
 *      Display the marathon classes from the system parameters.
512
 *
513
 *      This routine can only be utilized after the screen system
514
 *      has been initialized.
515
 *
516
 *  Parameters:
517
 *      operation       Operation to perform
518
 *
519
 *  Returns:
520
 *      Nothing
521
 *
522
 *========================================================================*/
523
 
524
void d_class( MARA_CFG * config, int operation )
525
{
526
    int         i, j, k;
527
    int         maxitr;                          /* Max number of definitions during update */
528
    int         opr;
529
 
530
    abort_flag = FALSE;
531
    if( operation == M_UPDATE )
532
    {
533
        opr = M_UPDATE;
534
        d_class( config, M_PREDISPLAY );         /* Force display before update */
535
    }
536
    else
537
    {
538
        opr = M_DISPLAY;
539
        clearscreen(  );
540
    }
541
 
542
    i = 0;                                       /* Set line 0 */
543
    d_field( 0, i++, "Category definitions", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY );
544
    i++;
545
 
546
    maxitr = ( operation == M_DISPLAY ) ? config->num_class : MAX_CLASS;
547
 
548
    for( j = 0, k = 0; j < maxitr; j++ )
549
    {
550
        bool        non_equestrian = FALSE;
551
 
552
        d_field( 0 + k, i, "Cat:", D_USTRING, 2, ( char * ) config->team_class[j].abr, TRUE, opr );
553
 
554
        if( ( config->team_class[j].abr[0] == config->nonequestrian_class_abr[0] )
555
            && ( config->team_class[j].abr[1] == config->nonequestrian_class_abr[1] ) )
556
        {
557
            non_equestrian = TRUE;
558
        }
559
 
560
        d_field( 8 + k, i, ":", D_STRING, LEN_CLASS_NAME,
561
                 config->team_class[j].full_name, TRUE, opr );
562
 
563
        if( !non_equestrian )
564
            d_field( LEN_CLASS_NAME + 10 + k, i, "Start:", D_TIME, 8,
565
                     ( char * ) &config->team_class[j].start, TRUE, opr );
566
 
567
        /*
568
         **  Step to next column or row
569
         */
570
        k += 40;
571
        if( !( ( j + 1 ) % 2 ) )
572
        {
573
            k = 0;
574
            i++;
575
        }
576
    }
577
}
578
 
579
/*========================================================================
580
 *
581
 *  Configuration Update and Display
582
 *
583
 *  Purpose:
584
 *      This function is called to Configuration Update and Display
585
 *
586
 *  Parameters:
587
 *      operation       Operation to perform
588
 *
589
 *  Returns:
590
 *      Nothing
591
 *
592
 *========================================================================*/
593
 
594
void d_config( MARA_CFG * config, int operation )
595
{
596
    int         i, j, k;
597
    int         maxitr;                          /* Max number of definitions during update */
598
    int         opr;
599
 
600
    abort_flag = FALSE;
601
    if( operation == M_UPDATE )
602
    {
603
        opr = M_UPDATE;
604
        d_config( config, M_PREDISPLAY );        /* Force display before update */
605
    }
606
    else
607
    {
608
        opr = M_DISPLAY;
609
        clearscreen(  );
610
    }
611
    i = 0;                                       /* Set line 0 */
612
 
613
    d_field( 0, i++, "Marathon configuration", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY );
614
    d_field( 0, ++i, "Name: ", D_STRING, MAX_EVENT_NAME, config->event_name, TRUE, opr );
615
 
616
    /*
617
     * display the leg names 
618
     */
619
 
620
    i += 2;
621
    maxitr = ( operation == M_DISPLAY ) ? config->num_legs : MAX_LEGS;
622
    for( j = 1; j <= maxitr; j++, i++ )
623
    {
624
        d_field( 0, i, "Leg ", D_NUMBER, 1, ( char * ) &j, TRUE, M_DISPLAY );
625
        d_field( 6, i, ": ", D_STRING, MAX_LEG_NAME, config->leg_name[j - 1], TRUE, opr );
626
    }
627
    abort_flag = FALSE;                          /* Trap aborts at the next field */
628
 
629
 
630
    /*
631
     * Display the team break definitions 
632
     */
633
 
634
    i++;
635
 
636
    d_field( 0, i++, "Valid team numbers are in the following ranges", D_NULL,
637
             0, ( char * ) 0, TRUE, M_DISPLAY );
638
 
639
    maxitr = ( operation == M_DISPLAY ) ? config->num_teams : MAX_TMS_SPLIT;
640
    for( k = 0, j = 0; j < maxitr; j++ )
641
    {
642
        d_field( k + 0, i, "From ", D_NUMBER, 4, ( char * ) &config->t_def[j].start, TRUE, opr );
643
        d_field( k + 9, i, " to ", D_NUMBER, 4, ( char * ) &config->t_def[j].end, TRUE, opr );
644
        k += 20;
645
        if( !( ( j + 1 ) % 4 ) )
646
        {
647
            k = 0;
648
            i++;
649
        }
650
    }
651
 
652
    /*
653
     * Name of legend config->addendum file 
654
     */
655
 
656
    abort_flag = FALSE;
657
    i++;
658
    d_field( 0, i++, "Legend addendum file :", D_STRING,
659
             ( int ) sizeof( config->addendum ) - 1, ( char * ) config->addendum, TRUE, opr );
660
 
661
    /*
662
     * Name of the alternate data file 
663
     */
664
    d_field( 0, i++, "Data filename :", D_STRING,
665
             ( int ) sizeof( config->datafilename ) - 1,
666
             ( char * ) config->datafilename, TRUE, opr );
667
 
668
    /*
669
     **  Non-equestrian configuration information
670
     */
671
    abort_flag = FALSE;
672
    i++;
673
    d_field( 0, i++, "Equestrian Leg :", D_NUMBER, 1, ( char * ) &config->equestrian_leg, TRUE, opr );
674
    d_field( 0, i++, "Non-Equestrian Category :", D_USTRING,
675
             ( int ) sizeof( config->nonequestrian_class_abr ) - 1,
676
             ( char * ) config->nonequestrian_class_abr, TRUE, opr );
677
 
678
    /*
679
    **  Print control
680
    */
681
    abort_flag = FALSE;
682
    i++;
683
    d_field(  0, i,   "Lines Per Page :", D_NUMBER, 3, ( char * ) &config->lines_per_page, TRUE, opr );
684
    d_field( 30, i++, "Perf Skip :", D_NUMBER, 1, ( char * ) &config->perf_skip, TRUE, opr );
685
}
686
 
687
/*========================================================================
688
 *
689
 *  Display the current country list
690
 *
691
 *  Purpose:
692
 *      This function is called to Display the current country list
693
 *
694
 *  Parameters:
695
 *      None
696
 *
697
 *  Returns:
698
 *      Nothing
699
 *
700
 *========================================================================*/
701
 
702
void display_country( void )
703
{
704
    d_cntry( &config, M_DISPLAY );
705
 
706
    cur( 0, n_lines - 1 );
707
    printf( "Any key to return to main menu :" );
708
    ( void ) getinp(  );
709
}
710
 
711
/*========================================================================
712
 *
713
 *  Define a new entry in the county list
714
 *
715
 *  Purpose:
716
 *      This function is called to Define a new entry in the county list
717
 *
718
 *  Parameters:
719
 *      None
720
 *
721
 *  Returns:
722
 *      Nothing
723
 *
724
 *========================================================================*/
725
 
726
void define_country( void )
727
{
728
    int         error;
729
    ty_t_country *ptr;
730
    int         i;
731
 
732
    /*
733
     **  Copy working configuration into a temp structure for
734
     **  use within the function
735
     */
736
    new = config;
737
 
738
    do
739
    {
740
        error = 0;
741
        new.num_countries = 0;
742
 
743
        /*
744
         * Get the operator to update the screen 
745
         */
746
 
747
        d_cntry( &new, M_UPDATE );               /* Update the country data */
748
        printf( "\n" );
749
 
750
        /*
751
         * Now check the data that has been entered. 
752
         */
753
 
754
        ptr = new.country_name;
755
        for( i = 0; i < MAX_COUNTRY; i++, ptr++ )
756
        {
757
            compact( ptr->abr );
758
            compact( ptr->full_name );
759
            if( ( ptr->abr[0] == '\0' ) != ( ptr->full_name[0] == '\0' ) )
760
            {
761
                error++;
762
                printf( "Missing field\n" );
763
            }
764
            if( ptr->abr[0] )
765
                new.num_countries++;
766
        }
767
 
768
        if( error )
769
        {
770
            printf( "Configuration error - error must be corrected\n" );
771
            printf( "Any key to continue " );
772
            ( void ) getinp(  );
773
        }
774
        else
775
        {
776
            printf( "Install configuration (Y)es, (D)iscard, (E)dit again :" );
777
            switch ( getfnc( "*YDEA" ) )
778
            {
779
            case 'Y':
780
                config = new;
781
                wt_config(  );                   /* Write out the data */
782
                break;
783
 
784
            case 'D':
785
                break;
786
 
787
            default:
788
                error = TRUE;
789
                break;
790
            }
791
        }
792
    } while( error );
793
    return;
794
}
795
 
796
 
797
/*========================================================================
798
 *
799
 *  Display / Update Country list
800
 *
801
 *  Purpose:
802
 *      This function is called to Display or Update Country list
803
 *
804
 *  Parameters:
805
 *      operation           Operation to perform
806
 *
807
 *  Returns:
808
 *      Nothing
809
 *
810
 *========================================================================*/
811
 
812
void d_cntry( MARA_CFG * config, int operation )
813
{
814
    int         i, j, k;
815
    int         opr;
816
 
817
    abort_flag = FALSE;
818
    if( operation == M_UPDATE )
819
    {
820
        opr = M_UPDATE;
821
        d_cntry( config, M_PREDISPLAY );         /* Force display before update */
822
    }
823
    else
824
    {
825
        opr = M_DISPLAY;
826
        clearscreen(  );
827
    }
828
    i = 0;                                       /* Set line 0 */
829
 
830
    d_field( 0, i++, "Country classifications", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY );
831
 
832
    /*
833
     * Display the country names 
834
     */
835
 
836
    i++;
837
 
838
    for( j = 0, k = 0; j < MAX_COUNTRY; j++ )
839
    {
840
        d_field( 0 + k, i, "Country: ", D_STRING, 4,
841
                 ( char * ) config->country_name[j].abr, TRUE, opr );
842
        d_field( 13 + k, i, ": ", D_STRING, LEN_CNTRY_NAME,
843
                 config->country_name[j].full_name, TRUE, opr );
844
 
845
        k += 40;
846
        if( !( ( j + 1 ) % 2 ) )
847
        {
848
            k = 0;
849
            i++;
850
        }
851
    }
852
}
853
 
854
/*========================================================================
855
 *
856
 *  Display the Winners List
857
 *
858
 *  Purpose:
859
 *      This function is called to Display the current winners list
860
 *
861
 *  Parameters:
862
 *      None
863
 *
864
 *  Returns:
865
 *      Nothing
866
 *
867
 *========================================================================*/
868
 
869
void display_winners( void )
870
{
871
    calc_class_summary( & class_summary );
872
    d_winners( &config, M_DISPLAY );
873
 
874
    cur( 0, n_lines - 1 );
875
    printf( "Any key to return to main menu :" );
876
    ( void ) getinp(  );
877
}
878
 
879
/*========================================================================
880
 *
881
 *  Update the winners information
882
 *
883
 *  Purpose:
884
 *      This function is called to update the winners information
885
 *
886
 *  Parameters:
887
 *      None
888
 *
889
 *  Returns:
890
 *      Nothing
891
 *
892
 *========================================================================*/
893
 
894
bool define_winners( void )
895
{
896
    int         error;
897
    int         i;
898
    bool        changed = FALSE;
899
 
900
    /*
901
    **  Update the class summary info to give the user a hint
902
    */
903
    calc_class_summary( & class_summary );
904
 
905
    /*
906
     **  Copy working configuration into a temp structure for
907
     **  use within the function
908
     */
909
    new = config;
910
 
911
    /*
912
    **  Edit and sanity test the cnfig data until the user is happy
913
    **  with it - or is ready to discard it.
914
    */
915
    do
916
    {
917
        error = 0;
918
        d_winners ( &new, M_UPDATE );
919
        printf( "\n" );
920
 
921
        /*
922
        **  Sanity test of the data
923
        */
924
        for( i = 0; i < MAX_CLASS; i++ )
925
        {
926
            if( new.team_class[i].abr[0] != '\0' && new.class_winners[i] == 0 )
927
            {
928
                printf( "  Warning: Class without winners: %s\n", new.team_class[i].abr );
929
            }
930
 
931
            if ( new.class_winners[i] > class_summary.class[i+1].total )
932
            {
933
                printf( "  Warning: Num winners greater than those in class: %s\n", new.team_class[i].abr );
934
            }
935
        }
936
 
937
 
938
        new.num_fame = 0;
939
        for( i = 0; i < MAX_FAME; i++ )
940
            if( new.hall_fame[i][0] )
941
                new.num_fame++;
942
 
943
        for( i = new.num_fame; i < MAX_FAME; i++ )
944
            if( new.hall_fame[i][0] )
945
            {
946
                printf( "Configuration error: Missing Fame name. Gaps not allowed\n" );
947
                error++;
948
                break;
949
            }
950
 
951
        abort_flag = FALSE;
952
        if( error )
953
        {
954
            printf( "Any key to continue " );
955
            getinp(  );
956
        }
957
        else
958
        {
959
            printf( "Install configuration (Y)es, (D)iscard, (E)dit again :" );
960
            switch ( getfnc( "*YDEA" ) )
961
            {
962
            case 'Y':
963
                config = new;
964
                wt_config(  );
965
                changed = TRUE;
966
                break;
967
 
968
            case 'D':
969
                break;
970
 
971
            default:
972
                error = TRUE;
973
                break;
974
            }
975
        }
976
    } while( error && ! abort_flag );
977
    return ( changed );
978
}
979
 
980
 
981
/*========================================================================
982
 *
983
 *  Display / Update winners list
984
 *
985
 *  Purpose:
986
 *      This function is called to Display or Update winners list
987
 *
988
 *  Parameters:
989
 *      operation           Operation to perform
990
 *
991
 *  Returns:
992
 *      Nothing
993
 *
994
 *========================================================================*/
995
 
996
void d_winners( MARA_CFG * config, int operation )
997
{
998
    int         i, j, k;
999
    int         maxitr;                          /* Max number of definitions during update */
1000
    int         opr;
1001
 
1002
    abort_flag = FALSE;
1003
    if( operation == M_UPDATE )
1004
    {
1005
        opr = M_UPDATE;
1006
        d_winners( config, M_PREDISPLAY );         /* Force display before update */
1007
    }
1008
    else
1009
    {
1010
        opr = M_DISPLAY;
1011
        clearscreen(  );
1012
    }
1013
 
1014
    i = 0;                                       /* Set line 0 */
1015
    d_field( 0, i++, "Winner definitions", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY );
1016
    i++;
1017
 
1018
    maxitr = config->num_class;
1019
 
1020
    for( j = 0, k = 0; j < maxitr; j++ )
1021
    {
1022
        d_field( 0 + k, i, "Cat:", D_USTRING, 2, ( char * ) config->team_class[j].abr, TRUE, M_DISPLAY );
1023
 
1024
        d_field( 7 + k, i, ":", D_STRING, LEN_CLASS_NAME,
1025
                 config->team_class[j].full_name, TRUE, M_DISPLAY );
1026
 
1027
        d_field( LEN_CLASS_NAME + 9 + k, i, "Num:", D_NUMBER, 3,
1028
                     ( char * ) &class_summary.class[j+1].total, TRUE, M_DISPLAY );
1029
 
1030
        d_field( LEN_CLASS_NAME + 9 + 7 + k, i, "Win:", D_NUMBER, 3,
1031
                     ( char * ) &config->class_winners[j], TRUE, opr );
1032
 
1033
        /*
1034
         **  Step to next column or row
1035
         */
1036
        k += 40;
1037
        if( !( ( j + 1 ) % 2 ) )
1038
        {
1039
            k = 0;
1040
            i++;
1041
        }
1042
    }
1043
 
1044
    abort_flag =  FALSE;
1045
    i += 2;
1046
    d_field( 0, i++, "Hall of Fame", D_NULL, 0, ( char * ) 0, TRUE, M_DISPLAY );
1047
    for( j = 0, k = 0; j < MAX_FAME; j++ )
1048
    {
1049
        d_field( k, i, "Name : ", D_STRING, MAX_PERSON_NAME,
1050
                 &config->hall_fame[j], TRUE, opr );
1051
        k += 40;
1052
        if( !( ( j + 1 ) % 2 ) )
1053
        {
1054
            k = 0;
1055
            i++;
1056
        }
1057
    }
1058
}
1059
 
1060
 
1061
/*========================================================================
1062
 *
1063
 *  Read in the configuration file
1064
 *
1065
 *  Purpose:
1066
 *      This function is called to read in the configuration file
1067
 *
1068
 *  Parameters:
1069
 *      None
1070
 *
1071
 *  Returns:
1072
 *      Nothing
1073
 *
1074
 *========================================================================*/
1075
 
1076
bool rd_config( void )
1077
{
1078
    FILE       *fcon;
1079
    int         ok;
1080
 
1081
 
1082
    fcon = fopen( confile, "rb" );
1083
    if( ! fcon )
1084
    {
1085
        printf( "Configuration file %s not found\n", confile );
1086
        return ( FALSE );
1087
    }
1088
    ok = r_config( fcon );
1089
 
1090
    fclose( fcon );
1091
    return ( ok );
1092
}
1093
 
1094
/*========================================================================
1095
 *
1096
 *  Read in the configuration file
1097
 *
1098
 *  Purpose:
1099
 *      This function is called to read in the configuration file
1100
 *      NOTE: Must be maintained with the Writer function
1101
 *
1102
 *  Parameters:
1103
 *      fcon        File number of the config file
1104
 *
1105
 *  Returns:
1106
 *      FALSE if an error is encountered
1107
 *
1108
 *========================================================================*/
1109
 
1110
bool r_config( FILE *fcon )
1111
{
1112
    int         len;                             /* Length of data read */
1113
 
1114
    /*
1115
     * Event name 
1116
     */
1117
printf( "Reading: Event Name\n" );
1118
    len = fread( config.event_name, sizeof( config.event_name ), 1 , fcon );
1119
    if( len != 1 )
1120
        return ( FALSE );
1121
 
1122
    /*
1123
     * Leg names 
1124
     */
1125
printf( "Reading: Leg Names\n" );
1126
    len = fread( config.leg_name, sizeof( config.leg_name ), 1 , fcon );
1127
    if( len != 1 )
1128
        return ( FALSE );
1129
 
1130
    /*
1131
     * Team definitions 
1132
     */
1133
printf( "Reading: Team Defs\n" );
1134
 
1135
    len = fread( config.t_def, sizeof( config.t_def ), 1 , fcon );
1136
    if( len != 1 )
1137
        return ( FALSE );
1138
 
1139
    /*
1140
     * Number of legs 
1141
     */
1142
 
1143
printf( "Reading: Leg Nums\n" );
1144
    len = fread( &config.num_legs, sizeof( config.num_legs ), 1 , fcon );
1145
    if( len != 1)
1146
        return ( FALSE );
1147
 
1148
    /*
1149
     * Number of team splits 
1150
     */
1151
 
1152
printf( "Reading: Team Splits\n" );
1153
    len = fread( &config.num_teams, sizeof( config.num_teams ), 1 , fcon );
1154
    if( len != 1 )
1155
        return ( FALSE );
1156
 
1157
    config.min_team = config.t_def[0].start;
1158
    config.max_team = config.t_def[config.num_teams - 1].end;
1159
 
1160
    /*
1161
     * Class information 
1162
     */
1163
printf( "Reading: Class Data\n" );
1164
    len = fread( config.team_class, sizeof( config.team_class ), 1 , fcon );
1165
    if( len != 1 )
1166
        return ( FALSE );
1167
    len = fread( &config.num_class, sizeof( config.num_class ), 1 , fcon );
1168
    if( len != 1 )
1169
        return ( FALSE );
1170
 
1171
    /*
1172
     * Country list 
1173
     */
1174
 
1175
printf( "Reading: Country Data, Name\n" );
1176
    len = fread( config.country_name, sizeof( config.country_name ), 1 , fcon );
1177
    if( len != 1 )
1178
        return ( FALSE );
1179
printf( "Reading: Country Data, Number\n" );
1180
    len = fread( &config.num_countries, sizeof( config.num_countries ), 1 , fcon );
1181
    if( len != 1 )
1182
        return ( FALSE );
1183
 
1184
    /*
1185
     * Addendum file 
1186
     */
1187
 
1188
printf( "Reading: Addendum File\n" );
1189
    len = fread( config.addendum, sizeof( config.addendum ), 1 , fcon );
1190
    if( len != 1 )
1191
        return ( feof( fcon ) );
1192
 
1193
    /*
1194
     * Name of the data file 
1195
     */
1196
 
1197
printf( "Reading: Name of data file\n" );
1198
    len = fread( config.datafilename, sizeof( config.datafilename ) , 1 , fcon );
1199
    if( len != 1 )
1200
        return ( feof( fcon ) );
1201
 
1202
    /*
1203
     **  Non-equestrian configuration information
1204
     */
1205
printf( "Reading: NonEquest\n" );
1206
    len = fread( config.nonequestrian_class_abr, sizeof( config.nonequestrian_class_abr ), 1 , fcon );
1207
    if( len != 1 )
1208
        return ( feof( fcon ) );
1209
printf( "Reading: NonEquest-2\n" );
1210
    len = fread( &config.equestrian_leg, sizeof( config.equestrian_leg ), 1 , fcon );
1211
    if( len != 1 )
1212
        return ( FALSE );
1213
 
1214
    /*
1215
    **  .txt file output control. Lines per page and perf-skipping
1216
    */
1217
printf( "Reading: Output Control\n" );
1218
    len = fread( &config.lines_per_page, sizeof( config.lines_per_page ), 1 , fcon );
1219
    if( len != 1 )
1220
        return ( feof( fcon ) );
1221
 
1222
printf( "Reading: Output Control-2\n" );
1223
    len = fread( &config.perf_skip, sizeof( config.perf_skip ), 1 , fcon );
1224
    if( len != 1 )
1225
        return ( FALSE );
1226
 
1227
printf( "Reading: Winners Info\n" );
1228
    len = fread( &config.class_winners, sizeof( config.class_winners ), 1 , fcon );
1229
    if( len != 1 )
1230
        return ( FALSE );
1231
 
1232
printf( "Reading: Hall of Fame Info\n" );
1233
    len = fread( &config.hall_fame, sizeof( config.hall_fame ), 1 , fcon );
1234
    if( len != 1 )
1235
        return ( FALSE );
1236
 
1237
printf( "Reading: Hall of Fame Numbers\n" );
1238
    len = fread( &config.num_fame, sizeof( config.num_fame ), 1 , fcon );
1239
    if( len != 1 )
1240
        return ( feof( fcon ) );
1241
 
1242
 
1243
    return ( TRUE );
1244
}
1245
 
1246
/*========================================================================
1247
 *
1248
 *  Write out the configuration file
1249
 *
1250
 *  Purpose:
1251
 *      This function is called to write the configuration file
1252
 *      NOTE: Must be maintained with the Reader function
1253
 *
1254
 *  Parameters:
1255
 *      None
1256
 *
1257
 *  Returns:
1258
 *      FALSE   : Error encountered
1259
 *
1260
 *========================================================================*/
1261
 
1262
bool wt_config( void )
1263
{
1264
    FILE        *fcon;
1265
 
1266
    /*
1267
     **  Open as a binary file
1268
     */
1269
    fcon = fopen( confile, "wb" );
1270
    if( !fcon )
1271
        return ( FALSE );
1272
 
1273
    /*
1274
     **  Write out multiple structures
1275
     **     Event name
1276
     **     Leg names
1277
     **     Team definitions
1278
     **     Number of legs
1279
     **     Number fo team splits
1280
     **     Class information
1281
     **     Number of defined classes
1282
     **     Country list
1283
     **     Number of defined countries
1284
     **     Legend config.addendum file name
1285
     **     Data file name
1286
     */
1287
 
1288
    fwrite( config.event_name, sizeof( config.event_name ), 1, fcon );
1289
    fwrite( config.leg_name, sizeof( config.leg_name ), 1, fcon );
1290
    fwrite( config.t_def, sizeof( config.t_def ), 1, fcon );
1291
    fwrite( &config.num_legs, sizeof( config.num_legs ), 1, fcon );
1292
    fwrite( &config.num_teams, sizeof( config.num_teams ), 1, fcon );
1293
    fwrite( config.team_class, sizeof( config.team_class ), 1, fcon );
1294
    fwrite( &config.num_class, sizeof( config.num_class ), 1, fcon );
1295
    fwrite( config.country_name, sizeof( config.country_name ), 1, fcon );
1296
    fwrite( &config.num_countries, sizeof( config.num_countries ), 1, fcon );
1297
    fwrite( config.addendum, sizeof( config.addendum ), 1, fcon );
1298
    fwrite( config.datafilename, sizeof( config.datafilename ), 1, fcon );
1299
    fwrite( config.nonequestrian_class_abr, sizeof( config.nonequestrian_class_abr ), 1, fcon );
1300
    fwrite( &config.equestrian_leg, sizeof( config.equestrian_leg ), 1, fcon );
1301
    fwrite( &config.lines_per_page, sizeof( config.lines_per_page ), 1, fcon );
1302
    fwrite( &config.perf_skip, sizeof( config.perf_skip ), 1, fcon );
1303
    fwrite( &config.class_winners, sizeof( config.class_winners ), 1, fcon );
1304
    fwrite( &config.hall_fame, sizeof( config.hall_fame ), 1, fcon );
1305
    fwrite( &config.num_fame, sizeof( config.num_fame ), 1, fcon );
1306
 
1307
    fclose( fcon );
1308
    return ( TRUE );
1309
}
1310
 
1311
/*========================================================================
1312
 *
1313
 *  Qsort callback: Sort by team
1314
 *
1315
 *  Purpose:
1316
 *      Function used by the team definition sort operation
1317
 *      It will compare two entries of the team def structure and return an
1318
 *      integer for gt eq lt conditions.
1319
 *      Note : If the start is 0 the team entry does exist and is placed at the
1320
 *      end of the sorted list.
1321
 *
1322
 *  Parameters:
1323
 *      a           comparision entry
1324
 *      b           comparision entry
1325
 *
1326
 *  Returns:
1327
 *      gt, eq, lt as required
1328
 *
1329
 *========================================================================*/
1330
 
1331
int f_comp_int( const void *aa, const void *bb )
1332
{
1333
    const ty_t_def *a = aa;
1334
    const ty_t_def *b = bb;
1335
 
1336
    if( a->start == 0 )
1337
        return ( 1 );
1338
    else if( b->start == 0 )
1339
        return ( -1 );
1340
    else
1341
        return ( a->start - b->start );
1342
}
1343
 
1344
/*========================================================================
1345
 *
1346
 *  Compact a string
1347
 *
1348
 *  Purpose:
1349
 *      This function is called remove leading and trailing spaces from
1350
 *      a string. Treats other non-printing characters as leading
1351
 *      spaces. This solves a problem when importing data from a
1352
 *      Microsoft CSV file with empty fields.
1353
 *
1354
 *  Parameters:
1355
 *      str     Address of the string to compact
1356
 *
1357
 *  Returns:
1358
 *      Nothing
1359
 *
1360
 *========================================================================*/
1361
 
1362
void compact( char *str )
1363
{
1364
    char       *ptr;
1365
 
1366
    ptr = str;
1367
    while( *str && ( isspace( *str ) || !isprint( *str ) ) )
1368
        str++;
1369
    strcpy( ptr, str );
1370
}
1371
 
1372
/*========================================================================
1373
 *
1374
 *  Validate a team number
1375
 *
1376
 *  Purpose:
1377
 *      This function is called to validate a team number
1378
 *
1379
 *  Parameters:
1380
 *      x       Number to validate
1381
 *
1382
 *  Returns:
1383
 *      TRUE    : Valid
1384
 *      FALSE   : Not valid
1385
 *
1386
 *========================================================================*/
1387
 
1388
bool valid_field( int x )
1389
{
1390
    int         i;
1391
 
1392
    for( i = 0; i < config.num_teams; i++ )
1393
    {
1394
        if( x <= config.t_def[i].end && x >= config.t_def[i].start )
1395
            return ( TRUE );
1396
        if( x < config.t_def[i].start )
1397
            break;                               /* Because the list is sorted */
1398
    }
1399
    return ( FALSE );
1400
}
1401
 
1402
/*========================================================================
1403
 *
1404
 *  Get a class descriptor from existing text
1405
 *
1406
 *  Purpose:
1407
 *      This function is called to Get a class descriptor
1408
 *
1409
 *  Parameters:
1410
 *      text    - User text to examine
1411
 *      config  - configuration dtaa to use
1412
 *
1413
 *  Returns:
1414
 *      An integer which is the index into the  config.team_class array
1415
 *      The integer is in the range 1 .. num_class
1416
 *      A value fo zero indicates the text was not found.
1417
 *
1418
 *========================================================================*/
1419
 
1420
int lookup_class( char *text, MARA_CFG * config_ptr )
1421
{
1422
    int         i;
1423
 
1424
    if( config_ptr == NULL )
1425
        config_ptr = &config;
1426
 
1427
    /*
1428
     * Attempt to locate the entered class in the list of defined classes
1429
     */
1430
 
1431
    for( i = 0; i < config_ptr->num_class; i++ )
1432
    {
1433
        if( toupper(text[0]) == toupper(config_ptr->team_class[i].abr[0]) &&
1434
            toupper(text[1]) == toupper(config_ptr->team_class[i].abr[1]) )
1435
            return ( ++i );
1436
    }
1437
    return ( 0 );
1438
}
1439
 
1440
/********************************* EOF ***********************************/