Subversion Repositories svn1

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
172 - 1
#include "qmconfig.h"
2
#include "mainwindow.h"
3
#include <QFileDialog>
4
#include <QObject>
5
#include <QMessageBox>
174 - 6
#include <QFileInfo>
7
#include <QFile>
199 david 8
#include <QCoreApplication>
172 - 9
 
210 - 10
//#define DISPLAY_STRUCTURES
208 - 11
 
172 - 12
// Global Data
176 - 13
QmConfig    config;
172 - 14
 
176 - 15
 
174 - 16
/*
17
**  Local definitions
18
*/
19
char        datfile[20];                         /* Name of the data file */
20
char        filebase[20];                        /* Event file name base */
198 - 21
char        filepath[300];
172 - 22
 
199 david 23
 
176 - 24
void QmConfig::load(const QString &cnfFile)
172 - 25
{
208 - 26
#ifdef DISPLAY_STRUCTURES
27
    display_structures();
28
#endif
172 - 29
    fileName = cnfFile;
199 david 30
 
172 - 31
    if ( !fileName.endsWith(".cnf",Qt::CaseInsensitive))
32
    {
33
        fileName.append(".cnf");
34
    }
35
    if (cnfFile.isEmpty())
36
    {
37
        fileName = QFileDialog::getOpenFileName(0, "Select Config File",
174 - 38
                                                         filepath,
172 - 39
                                                         "Data (*.cnf);;All (*.*)",
40
                                                         0,
41
 
42
                                                         );
43
    }
44
 
45
    //  No file selected
46
    //  Just exit
47
    if (fileName.isEmpty())
48
    {
174 - 49
        qDebug("No Config file selected");
172 - 50
        exit(1);
51
    }
52
 
174 - 53
    //
227 - 54
    //  Setup file names
174 - 55
    //
56
    QFileInfo info (fileName);
57
    strncpy(filebase, qPrintable(info.baseName()), 8);
58
    strcpy( datfile, filebase );
59
    strcat( datfile, ".dat" );
60
 
61
    strncpy(filepath, qPrintable(info.absolutePath()), sizeof(filepath)-3);
62
    strcat(filepath, "/");
63
    qDebug("FilePath:%s", filepath );
64
 
172 - 65
    if ( !open_read_config() )
66
    {
67
        if (QMessageBox::Cancel == QMessageBox::question ( 0,
68
                                                       "Config Load Error",
69
                                                       "Cannot load or read configuration file.\n"
70
                                                       "If you continue a new configuration will be created\n"
71
                                                       "If you cancel then the application will terminate.",
72
                                                       QMessageBox::Ok | QMessageBox::Cancel
73
                                                       ) )
74
        {
174 - 75
            qDebug("Cancel to bad config");
172 - 76
            exit(2);
77
        }
78
    }
79
}
80
 
81
 
82
bool QmConfig::open_read_config( void )
83
{
84
    bool result;
85
    // Open the file
176 - 86
    QFile configFile;
172 - 87
    configFile.setFileName(fileName);
88
    if ( ! configFile.open(QIODevice::ReadOnly) )
89
    {
90
        MainWindow::showMessage("Cannot open config File");
91
        return (false );
92
    }
93
 
176 - 94
    result = read_config(configFile);
172 - 95
    configFile.close();
96
 
97
    if ( result )
98
    {
99
        /*
227 - 100
        **  Post read calculations and fixups
101
        */
176 - 102
        if( datafilename[0] )
172 - 103
        {
176 - 104
            strcpy( datfile, datafilename );
172 - 105
            strcat( datfile, ".dat" );
106
        }
176 - 107
        nonequestrian_class = lookup_class( nonequestrian_class_abr );
227 - 108
 
109
        class_ne_winners_by_class = false;
110
        for( int i = 0; i < MAX_CLASS; i++ )
111
        {
112
           if(class_ne_winners[i])
113
           {
114
               class_ne_winners_by_class = true;
115
               break;
116
           }
117
        }
118
 
119
 
172 - 120
    }
121
    return result;
122
}
123
 
124
/*========================================================================
125
 *
126
 *  Read in the configuration file
127
 *
128
 *  Purpose:
129
 *      This function is called to read in the configuration file
130
 *      NOTE: Must be maintained with the Writer function
131
 *
132
 *  Parameters:
133
 *      fcon        File number of the config file
134
 *
135
 *  Returns:
136
 *      FALSE if an error is encountered
137
 *
138
 *========================================================================*/
139
 
176 - 140
bool QmConfig::read_config( QFile &configFile  )
172 - 141
{
142
    int         len;                            /* Length of data read */
143
    int         fsize;                          /* Length of desired data */
144
 
145
    /*
146
     * Event name
147
     */
210 - 148
//qDebug( "Reading: Event Name" );
176 - 149
    fsize = sizeof( event_name );
150
    len = configFile.read( event_name, fsize );
172 - 151
    if( len != fsize )
152
        return ( FALSE );
153
 
154
    /*
155
     * Leg names
156
     */
210 - 157
//qDebug( "Reading: Leg Names" );
176 - 158
    fsize = sizeof( leg_name );
159
    len = configFile.read( (char *)leg_name, fsize );
172 - 160
    if( len != fsize )
161
        return ( FALSE );
162
 
163
    /*
164
     * Team definitions
165
     */
210 - 166
//qDebug( "Reading: Team Defs" );
176 - 167
    fsize = sizeof( t_def  );
168
    len = configFile.read( (char *)t_def, fsize );
172 - 169
    if( len != fsize )
170
        return ( FALSE );
171
 
172
    /*
173
     * Number of legs
174
     */
175
 
210 - 176
//qDebug( "Reading: Leg Nums" );
176 - 177
    fsize = sizeof( num_legs  );
178
    len = configFile.read( (char *)&num_legs, fsize );
172 - 179
    if( len != fsize)
180
        return ( FALSE );
181
 
182
    /*
183
     * Number of team splits
184
     */
185
 
210 - 186
//qDebug( "Reading: Team Splits" );
176 - 187
    fsize = sizeof( num_teams  );
188
    len = configFile.read( (char *)&num_teams, fsize );
172 - 189
    if( len != fsize )
190
        return ( FALSE );
191
 
176 - 192
    min_team = t_def[0].start;
193
    max_team = t_def[num_teams - 1].end;
172 - 194
 
195
    /*
196
     * Class information
197
     */
210 - 198
//qDebug( "Reading: Class Data" );
176 - 199
    fsize = sizeof( team_class  );
200
    len = configFile.read( (char *)team_class, fsize );
172 - 201
    if( len != fsize )
202
        return ( FALSE );
176 - 203
    fsize = sizeof( num_class  );
204
    len = configFile.read( (char *)&num_class, fsize);
172 - 205
    if( len != fsize )
206
        return ( FALSE );
207
 
208
    /*
209
     * Country list
210
     */
211
 
210 - 212
//qDebug( "Reading: Country Data, Name" );
176 - 213
    fsize = sizeof( country_name  );
214
    len = configFile.read( (char *)country_name, fsize );
172 - 215
    if( len != fsize )
216
        return ( FALSE );
217
 
210 - 218
//qDebug( "Reading: Country Data, Number" );
176 - 219
    fsize = sizeof( num_countries  );
220
    len = configFile.read( (char *)&num_countries, fsize );
172 - 221
    if( len != fsize )
222
        return ( FALSE );
223
 
224
    /*
225
     * Addendum file
226
     */
227
 
210 - 228
//qDebug( "Reading: Addendum File" );
176 - 229
    fsize = sizeof( addendum );
230
    len = configFile.read( addendum, fsize );
172 - 231
    if( len != fsize )
232
        return ( configFile.atEnd() );
233
 
234
    /*
235
     * Name of the data file
236
     */
237
 
210 - 238
//qDebug( "Reading: Name of data file" );
176 - 239
    fsize = sizeof( datafilename );
240
    len = configFile.read( datafilename, fsize );
172 - 241
    if( len != fsize )
242
        return ( configFile.atEnd() );
243
 
244
    /*
245
     **  Non-equestrian configuration information
246
     */
210 - 247
//qDebug( "Reading: NonEquest" );
176 - 248
    fsize = sizeof( nonequestrian_class_abr );
249
    len = configFile.read( nonequestrian_class_abr, fsize );
172 - 250
    if( len != fsize )
251
        return ( configFile.atEnd() );
252
 
210 - 253
//qDebug( "Reading: NonEquest-2" );
176 - 254
    fsize = sizeof( equestrian_leg );
255
    len = configFile.read( (char *)&equestrian_leg, fsize );
172 - 256
    if( len != fsize )
257
        return ( FALSE );
258
 
259
    /*
260
    **  .txt file output control. Lines per page and perf-skipping
261
    */
210 - 262
//qDebug( "Reading: Output Control" );
176 - 263
    fsize = sizeof( lines_per_page );
264
    len = configFile.read( (char *)&lines_per_page, fsize );
172 - 265
    if( len != fsize )
266
        return ( configFile.atEnd() );
267
 
210 - 268
//qDebug( "Reading: Output Control-2" );
176 - 269
    fsize = sizeof( perf_skip );
270
    len = configFile.read( (char *)&perf_skip, fsize );
172 - 271
    if( len != fsize )
272
        return ( FALSE );
273
 
210 - 274
//qDebug( "Reading: Winners Info" );
176 - 275
    fsize = sizeof( class_winners );
276
    len = configFile.read( (char *)&class_winners, fsize );
172 - 277
    if( len != fsize )
278
        return ( FALSE );
279
 
210 - 280
//qDebug( "Reading: Hall of Fame Info" );
176 - 281
    fsize = sizeof( hall_fame );
282
    len = configFile.read( (char *)&hall_fame, fsize );
172 - 283
    if( len != fsize )
284
        return ( FALSE );
285
 
210 - 286
//qDebug( "Reading: Hall of Fame Numbers" );
208 - 287
    fsize = sizeof( num_fame );
176 - 288
    len = configFile.read( (char *)&num_fame, fsize );
172 - 289
    if( len != fsize )
290
        return ( configFile.atEnd() );
291
 
227 - 292
//qDebug( "Reading: NE Winners Info" );
293
        fsize = sizeof( class_ne_winners );
294
        len = configFile.read( (char *)&class_ne_winners, fsize );
295
        if( len != fsize )
296
             return ( configFile.atEnd() );
172 - 297
 
297 david 298
//qDebug( "Reading: Web Import Url" );
299
        fsize = sizeof( webUrl );
300
        len = configFile.read( (char *)&webUrl, fsize );
301
        if( len != fsize )
302
            return ( configFile.atEnd() );
303
 
172 - 304
    return ( TRUE );
305
}
306
 
199 david 307
/*----------------------------------------------------------------------------
308
** FUNCTION           : getAddendemFile
309
**
310
** DESCRIPTION        : Returns the full path the the addemdum file
315 david 311
**                      The function will look for the file in a number of
199 david 312
**                      locations
313
**
314
**
315
** INPUTS             : name    - Name of the addenum file
316
**                      create  - True. Allow file to be created
317
**
318
** RETURNS            : NULL    - No addendum name, or file not found
319
**                                If create' is true then the preferred
320
**                                location will be returned.
321
**
322
----------------------------------------------------------------------------*/
172 - 323
 
199 david 324
 
315 david 325
const QString QmConfig::getAddendemFile(const QString &name, bool create )
199 david 326
{
327
    if (name.isEmpty())
328
        return NULL;
329
 
330
    QFile file;
331
    QString addendumFileName;
332
    addendumFileName = filepath;
333
    addendumFileName.append(name);
334
    QString addendumFileNamePreferred(addendumFileName);
335
    file.setFileName(addendumFileName);
200 david 336
    //qDebug("Try:%s", qPrintable(addendumFileName));
199 david 337
    if ( !file.exists())
338
    {
339
        addendumFileName = QCoreApplication::applicationDirPath ();
340
        addendumFileName.append("/");
341
        addendumFileName.append(name);
342
        file.setFileName(addendumFileName);
200 david 343
        //qDebug("Try:%s", qPrintable(addendumFileName));
199 david 344
        if ( !file.exists())
345
        {
346
             addendumFileName = QDir::currentPath ();
347
             addendumFileName.append("/");
348
             addendumFileName.append(name);
349
             file.setFileName(addendumFileName);
200 david 350
             //qDebug("Try:%s", qPrintable(addendumFileName));
199 david 351
             if ( !file.exists())
352
             {
200 david 353
                 //qDebug("Addeddum File not found");
199 david 354
                 if (create)
355
                 {
356
                     addendumFileName = addendumFileNamePreferred;
357
                 }
358
                 else
359
                 {
360
                     return NULL;
361
                 }
362
             }
363
        }
364
    }
315 david 365
    return addendumFileName;
199 david 366
}
367
 
172 - 368
/*========================================================================
369
 *
370
 *  Write out the configuration file
371
 *
372
 *  Purpose:
373
 *      This function is called to write the configuration file
374
 *      NOTE: Must be maintained with the Reader function
375
 *
376
 *  Parameters:
377
 *      None
378
 *
379
 *  Returns:
380
 *      FALSE   : Error encountered
381
 *
382
 *========================================================================*/
383
 
384
bool QmConfig::write_config( void )
385
{
174 - 386
    if (fileName.isEmpty())
387
    {
388
        qDebug("No Config file selected");
389
        return(false);
390
    }
172 - 391
    /*
392
     **  Open as a binary file
393
     */
174 - 394
    QFile file;
395
    file.setFileName(fileName);
172 - 396
    if ( ! file.open(QIODevice::WriteOnly | QIODevice::Truncate) )
397
    {
174 - 398
        qDebug("File error: %s", qPrintable(file.errorString()));
218 david 399
        MainWindow::showMessage("Cannot write config file");
172 - 400
        return (false);
401
    }
402
 
403
     /*
404
     **  Write out multiple structures
405
     **     Event name
406
     **     Leg names
407
     **     Team definitions
408
     **     Number of legs
409
     **     Number fo team splits
410
     **     Class information
411
     **     Number of defined classes
412
     **     Country list
413
     **     Number of defined countries
176 - 414
     **     Legend addendum file name
172 - 415
     **     Data file name
416
     */
417
 
176 - 418
    file.write( (const char *) event_name, sizeof( event_name ) );
419
    file.write( (const char *) leg_name, sizeof( leg_name ) );
420
    file.write( (const char *) t_def, sizeof( t_def ) );
421
    file.write( (const char *) &num_legs, sizeof( num_legs ) );
422
    file.write( (const char *) &num_teams, sizeof( num_teams ) );
423
    file.write( (const char *) team_class, sizeof( team_class ) );
424
    file.write( (const char *) &num_class, sizeof( num_class ) );
425
    file.write( (const char *) country_name, sizeof( country_name ) );
426
    file.write( (const char *) &num_countries, sizeof( num_countries ) );
427
    file.write( (const char *) addendum, sizeof( addendum ) );
428
    file.write( (const char *) datafilename, sizeof( datafilename ) );
429
    file.write( (const char *) nonequestrian_class_abr, sizeof( nonequestrian_class_abr ) );
430
    file.write( (const char *) &equestrian_leg, sizeof( equestrian_leg ) );
431
    file.write( (const char *) &lines_per_page, sizeof( lines_per_page ) );
432
    file.write( (const char *) &perf_skip, sizeof( perf_skip ) );
433
    file.write( (const char *) &class_winners, sizeof( class_winners ) );
434
    file.write( (const char *) &hall_fame, sizeof( hall_fame ) );
435
    file.write( (const char *) &num_fame, sizeof( num_fame ) );
227 - 436
    file.write( (const char *) &class_ne_winners, sizeof( class_ne_winners ) );
297 david 437
    file.write( (const char *) &webUrl, sizeof( webUrl ) );
172 - 438
 
439
    file.close();
440
    return ( TRUE );
441
}
174 - 442
 
443
/*========================================================================
444
 *
445
 *  Qsort callback: Sort by team
446
 *
447
 *  Purpose:
448
 *      Function used by the team definition sort operation
449
 *      It will compare two entries of the team def structure and return an
450
 *      integer for gt eq lt conditions.
451
 *      Note : If the start is 0 the team entry does exist and is placed at the
452
 *      end of the sorted list.
453
 *
454
 *  Parameters:
455
 *      a           comparision entry
456
 *      b           comparision entry
457
 *
458
 *  Returns:
459
 *      gt, eq, lt as required
460
 *
461
 *========================================================================*/
462
 
463
int f_comp_int( const void *aa, const void *bb )
464
{
465
    const ty_t_def *a = (ty_t_def *)aa;
466
    const ty_t_def *b = (ty_t_def *)bb;
467
 
468
    if( a->start == 0 )
469
        return ( 1 );
470
    else if( b->start == 0 )
471
        return ( -1 );
472
    else
473
        return ( a->start - b->start );
474
}
475
 
476
/*========================================================================
477
 *
478
 *  Compact a string
479
 *
480
 *  Purpose:
481
 *      This function is called remove leading and trailing spaces from
482
 *      a string. Treats other non-printing characters as leading
483
 *      spaces. This solves a problem when importing data from a
484
 *      Microsoft CSV file with empty fields.
485
 *
486
 *  Parameters:
487
 *      str     Address of the string to compact
488
 *
489
 *  Returns:
490
 *      Nothing
491
 *
492
 *========================================================================*/
493
 
494
void compact( char *str )
495
{
496
    char       *ptr;
497
 
498
    ptr = str;
499
    while( *str && ( isspace( *str ) || !isprint( *str ) ) )
500
        str++;
501
    strcpy( ptr, str );
502
}
503
 
504
/*========================================================================
505
 *
506
 *  Validate a team number
507
 *
508
 *  Purpose:
509
 *      This function is called to validate a team number
510
 *
511
 *  Parameters:
512
 *      x       Number to validate
513
 *
514
 *  Returns:
515
 *      TRUE    : Valid
516
 *      FALSE   : Not valid
517
 *
518
 *========================================================================*/
519
 
520
bool valid_field( int x )
521
{
522
    int         i;
523
 
524
    for( i = 0; i < config.num_teams; i++ )
525
    {
526
        if( x <= config.t_def[i].end && x >= config.t_def[i].start )
527
            return ( TRUE );
528
        if( x < config.t_def[i].start )
529
            break;                               /* Because the list is sorted */
530
    }
531
    return ( FALSE );
532
}
533
 
534
/*========================================================================
535
 *
536
 *  Get a class descriptor from existing text
537
 *
538
 *  Purpose:
539
 *      This function is called to Get a class descriptor
540
 *
541
 *  Parameters:
542
 *      text    - User text to examine
543
 *      config  - configuration dtaa to use
544
 *
545
 *  Returns:
546
 *      An integer which is the index into the  config.team_class array
547
 *      The integer is in the range 1 .. num_class
548
 *      A value fo zero indicates the text was not found.
549
 *
550
 *========================================================================*/
551
 
176 - 552
int QmConfig::lookup_class( const char *text )
174 - 553
{
554
    int         i;
555
 
176 - 556
//    if( config_ptr == NULL )
557
//        config_ptr = &config;
174 - 558
 
559
    /*
560
     * Attempt to locate the entered class in the list of defined classes
561
     */
562
 
176 - 563
    for( i = 0; i < num_class; i++ )
174 - 564
    {
176 - 565
        if( toupper(text[0]) == toupper(team_class[i].abr[0]) &&
566
            toupper(text[1]) == toupper(team_class[i].abr[1]) )
174 - 567
            return ( ++i );
568
    }
569
    return ( 0 );
570
}
177 - 571
 
572
#ifdef DISPLAY_STRUCTURES
573
/*============================================================================
574
**
575
**  Display structure information
576
**
577
**  Purpose:    Display internal structure information
578
**
579
**  Parameters: Nothing
580
**
581
**  Returns:    Nothing directly
582
**
583
**===========================================================================*/
584
 
585
/*
586
**  esize - A macro to return the size of a structure element
587
**  element - print element information
588
*/
589
#define esize( st, el) ( sizeof(((st *)0)->el))
590
#define element( st, el) \
208 - 591
    printf( "Offset of %-15s :%4d, Size:%d", #el, offsetof( st, el), esize(st, el) );
209 - 592
#define element2( st, el) \
593
    printf( "Size of %-15s :%4d", #el, esize(st, el) );
177 - 594
 
595
void display_structures(void)
596
{
208 - 597
    printf( "Structure: leg_type" );
177 - 598
    element( leg_type, start    );
599
    element( leg_type, end      );
600
    element( leg_type, elapsed  );
601
    element( leg_type, l_place  );
602
    element( leg_type, le_place );
603
    element( leg_type, lc_place );
604
    element( leg_type, lec_place);
605
    element( leg_type, manual   );
208 - 606
    printf( "Sizeof %-18s :%4d", "leg_type", sizeof(leg_type) );
177 - 607
 
608
 
208 - 609
    printf( "" );
610
    printf( "Structure: team_type" );
177 - 611
    element( team_type, numb   );
612
    element( team_type, name   );
613
    element( team_type, leg    );
614
    element( team_type, members);
208 - 615
    element( team_type, teamclass  );
177 - 616
    element( team_type, country);
617
    element( team_type, flags  );
208 - 618
    printf( "Sizeof %-18s :%4d", "team_type", sizeof(team_type) );
177 - 619
 
209 - 620
#if 1
208 - 621
    printf( "" );
622
    printf( "Structure: MARA_CFG" );
209 - 623
    element2( QmConfig, event_name      );
624
    element2( QmConfig, leg_name        );
625
    element2( QmConfig, t_def           );
626
    element2( QmConfig, num_legs        );
627
    element2( QmConfig, num_teams       );
628
    element2( QmConfig, max_team        );
629
    element2( QmConfig, min_team        );
630
    element2( QmConfig, team_class      );
631
    element2( QmConfig, num_class       );
632
    element2( QmConfig, country_name    );
633
    element2( QmConfig, num_countries   );
634
    element2( QmConfig, addendum        );
635
    element2( QmConfig, datafilename    );
636
    printf( "Sizeof %-18s :%4d", "QmConfig", sizeof(QmConfig) );
208 - 637
#endif
177 - 638
}
639
#endif