Subversion Repositories svn1

Rev

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