#include "qmconfig.h" #include "mainwindow.h" #include #include #include #include #include #include #include //#define DISPLAY_STRUCTURES // Global Data QmConfig config; // Application Config // Only use this to store user setting // Thinks like : // Last path for loaded file // Last entered uploaded leg // Swim Start: Leg Set up Delta and base QSettings *appSettings = NULL; /* ** Local definitions */ char datfile[20]; /* Name of the data file */ char filebase[20]; /* Event file name base */ char filepath[300]; /*---------------------------------------------------------------------------- ** FUNCTION : QmConfig ** ** DESCRIPTION : Constructor ** ** ** INPUTS : ** ----------------------------------------------------------------------------*/ QmConfig::QmConfig(void) { /* ** Init appSettings - once ! */ //qDebug("Create a QmConfig"); if (!appSettings) { appSettings = new QSettings(getAddendemFile("mara.ini", true), QSettings::IniFormat); } } /*---------------------------------------------------------------------------- ** FUNCTION : ~QmConfig ** ** DESCRIPTION : Destructor ** ** ----------------------------------------------------------------------------*/ QmConfig::~QmConfig() { /* ** This will force the items to be flushed */ if (appSettings) { delete(appSettings); appSettings = NULL; } } void QmConfig::load(const QString &cnfFile) { #ifdef DISPLAY_STRUCTURES display_structures(); #endif fileName = cnfFile; if ( !fileName.endsWith(".cnf",Qt::CaseInsensitive)) { fileName.append(".cnf"); } if (cnfFile.isEmpty()) { fileName = QFileDialog::getOpenFileName(0, "Select Config File", filepath, "Data (*.cnf);;All (*.*)", 0, 0 ); } // No file selected // Just exit if (fileName.isEmpty()) { qDebug("No Config file selected"); exit(1); } // // Setup file names // QFileInfo info (fileName); strncpy(filebase, qPrintable(info.baseName()), 8); strcpy( datfile, filebase ); strcat( datfile, ".dat" ); strncpy(filepath, qPrintable(info.absolutePath()), sizeof(filepath)-3); strcat(filepath, "/"); qDebug("FilePath:%s", filepath ); if ( !open_read_config() ) { if (QMessageBox::Cancel == QMessageBox::question ( 0, "Config Load Error", "Cannot load or read configuration file.\n" "If you continue a new configuration will be created\n" "If you cancel then the application will terminate.", QMessageBox::Ok | QMessageBox::Cancel ) ) { qDebug("Cancel to bad config"); exit(2); } } } bool QmConfig::open_read_config( void ) { bool result; // Open the file QFile configFile; configFile.setFileName(fileName); if ( ! configFile.open(QIODevice::ReadOnly) ) { MainWindow::showMessage("Cannot open config File"); return (false ); } result = read_config(configFile); configFile.close(); if ( result ) { /* ** Post read calculations and fixups */ if( datafilename[0] ) { strcpy( datfile, datafilename ); strcat( datfile, ".dat" ); } nonequestrian_class = lookup_class( nonequestrian_class_abr ); class_ne_winners_by_class = false; for( int i = 0; i < MAX_CLASS; i++ ) { if(class_ne_winners[i]) { class_ne_winners_by_class = true; break; } } } return result; } /*======================================================================== * * 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 QmConfig::read_config( QFile &configFile ) { int len; /* Length of data read */ int fsize; /* Length of desired data */ /* * Event name */ //qDebug( "Reading: Event Name" ); fsize = sizeof( event_name ); len = configFile.read( event_name, fsize ); if( len != fsize ) return ( FALSE ); /* * Leg names */ //qDebug( "Reading: Leg Names" ); fsize = sizeof( leg_name ); len = configFile.read( (char *)leg_name, fsize ); if( len != fsize ) return ( FALSE ); /* * Team definitions */ //qDebug( "Reading: Team Defs" ); fsize = sizeof( t_def ); len = configFile.read( (char *)t_def, fsize ); if( len != fsize ) return ( FALSE ); /* * Number of legs */ //qDebug( "Reading: Leg Nums" ); fsize = sizeof( num_legs ); len = configFile.read( (char *)&num_legs, fsize ); if( len != fsize) return ( FALSE ); /* * Number of team splits */ //qDebug( "Reading: Team Splits" ); fsize = sizeof( num_teams ); len = configFile.read( (char *)&num_teams, fsize ); if( len != fsize ) return ( FALSE ); min_team = t_def[0].start; max_team = t_def[num_teams - 1].end; /* * Class information */ //qDebug( "Reading: Class Data" ); fsize = sizeof( team_class ); len = configFile.read( (char *)team_class, fsize ); if( len != fsize ) return ( FALSE ); fsize = sizeof( num_class ); len = configFile.read( (char *)&num_class, fsize); if( len != fsize ) return ( FALSE ); /* * Country list */ //qDebug( "Reading: Country Data, Name" ); fsize = sizeof( country_name ); len = configFile.read( (char *)country_name, fsize ); if( len != fsize ) return ( FALSE ); //qDebug( "Reading: Country Data, Number" ); fsize = sizeof( num_countries ); len = configFile.read( (char *)&num_countries, fsize ); if( len != fsize ) return ( FALSE ); /* * Addendum file */ //qDebug( "Reading: Addendum File" ); fsize = sizeof( addendum ); len = configFile.read( addendum, fsize ); if( len != fsize ) return ( configFile.atEnd() ); /* * Name of the data file */ //qDebug( "Reading: Name of data file" ); fsize = sizeof( datafilename ); len = configFile.read( datafilename, fsize ); if( len != fsize ) return ( configFile.atEnd() ); /* ** Non-equestrian configuration information */ //qDebug( "Reading: NonEquest" ); fsize = sizeof( nonequestrian_class_abr ); len = configFile.read( nonequestrian_class_abr, fsize ); if( len != fsize ) return ( configFile.atEnd() ); //qDebug( "Reading: NonEquest-2" ); fsize = sizeof( equestrian_leg ); len = configFile.read( (char *)&equestrian_leg, fsize ); if( len != fsize ) return ( FALSE ); /* ** .txt file output control. Lines per page and perf-skipping */ //qDebug( "Reading: Output Control" ); fsize = sizeof( lines_per_page ); len = configFile.read( (char *)&lines_per_page, fsize ); if( len != fsize ) return ( configFile.atEnd() ); //qDebug( "Reading: Output Control-2" ); fsize = sizeof( perf_skip ); len = configFile.read( (char *)&perf_skip, fsize ); if( len != fsize ) return ( FALSE ); //qDebug( "Reading: Winners Info" ); fsize = sizeof( class_winners ); len = configFile.read( (char *)&class_winners, fsize ); if( len != fsize ) return ( FALSE ); //qDebug( "Reading: Hall of Fame Info" ); fsize = sizeof( hall_fame ); len = configFile.read( (char *)&hall_fame, fsize ); if( len != fsize ) return ( FALSE ); //qDebug( "Reading: Hall of Fame Numbers" ); fsize = sizeof( num_fame ); len = configFile.read( (char *)&num_fame, fsize ); if( len != fsize ) return ( configFile.atEnd() ); //qDebug( "Reading: NE Winners Info" ); fsize = sizeof( class_ne_winners ); len = configFile.read( (char *)&class_ne_winners, fsize ); if( len != fsize ) return ( configFile.atEnd() ); //qDebug( "Reading: Web Import Url" ); fsize = sizeof( webUrl ); len = configFile.read( (char *)&webUrl, fsize ); if( len != fsize ) return ( configFile.atEnd() ); //qDebug( "Reading: Awards Text File" ); fsize = sizeof( awardsfilename ); len = configFile.read( (char *)&awardsfilename, fsize ); if( len != fsize ) return ( configFile.atEnd() ); return ( TRUE ); } /*---------------------------------------------------------------------------- ** FUNCTION : getAddendemFile ** ** DESCRIPTION : Returns the full path the the addemdum file ** The function will look for the file in a number of ** locations ** ** ** INPUTS : name - Name of the addenum file ** create - True. Allow file to be created ** ** RETURNS : NULL - No addendum name, or file not found ** If create' is true then the preferred ** location will be returned. ** ----------------------------------------------------------------------------*/ const QString QmConfig::getAddendemFile(const QString &name, bool create ) { if (name.isEmpty()) return NULL; QFile file; QString addendumFileName; addendumFileName = filepath; addendumFileName.append(name); QString addendumFileNamePreferred(addendumFileName); file.setFileName(addendumFileName); //qDebug("Try:%s", qPrintable(addendumFileName)); if ( !file.exists()) { addendumFileName = QCoreApplication::applicationDirPath (); addendumFileName.append("/"); addendumFileName.append(name); file.setFileName(addendumFileName); //qDebug("Try:%s", qPrintable(addendumFileName)); if ( !file.exists()) { addendumFileName = QDir::currentPath (); addendumFileName.append("/"); addendumFileName.append(name); file.setFileName(addendumFileName); //qDebug("Try:%s", qPrintable(addendumFileName)); if ( !file.exists()) { //qDebug("Addeddum File not found"); if (create) { addendumFileName = addendumFileNamePreferred; } else { return NULL; } } } } return addendumFileName; } /*======================================================================== * * 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 QmConfig::write_config( void ) { if (fileName.isEmpty()) { qDebug("No Config file selected"); return(false); } /* ** Open as a binary file */ QFile file; file.setFileName(fileName); if ( ! file.open(QIODevice::WriteOnly | QIODevice::Truncate) ) { qDebug("File error: %s", qPrintable(file.errorString())); MainWindow::showMessage("Cannot write config file"); 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 addendum file name ** Data file name */ file.write( (const char *) event_name, sizeof( event_name ) ); file.write( (const char *) leg_name, sizeof( leg_name ) ); file.write( (const char *) t_def, sizeof( t_def ) ); file.write( (const char *) &num_legs, sizeof( num_legs ) ); file.write( (const char *) &num_teams, sizeof( num_teams ) ); file.write( (const char *) team_class, sizeof( team_class ) ); file.write( (const char *) &num_class, sizeof( num_class ) ); file.write( (const char *) country_name, sizeof( country_name ) ); file.write( (const char *) &num_countries, sizeof( num_countries ) ); file.write( (const char *) addendum, sizeof( addendum ) ); file.write( (const char *) datafilename, sizeof( datafilename ) ); file.write( (const char *) nonequestrian_class_abr, sizeof( nonequestrian_class_abr ) ); file.write( (const char *) &equestrian_leg, sizeof( equestrian_leg ) ); file.write( (const char *) &lines_per_page, sizeof( lines_per_page ) ); file.write( (const char *) &perf_skip, sizeof( perf_skip ) ); file.write( (const char *) &class_winners, sizeof( class_winners ) ); file.write( (const char *) &hall_fame, sizeof( hall_fame ) ); file.write( (const char *) &num_fame, sizeof( num_fame ) ); file.write( (const char *) &class_ne_winners, sizeof( class_ne_winners ) ); file.write( (const char *) &webUrl, sizeof( webUrl ) ); file.write( (const char *) &awardsfilename, sizeof( awardsfilename ) ); file.close(); 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 = (ty_t_def *)aa; const ty_t_def *b = (ty_t_def *)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 QmConfig::lookup_class( const char *text ) { 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 < num_class; i++ ) { if( toupper(text[0]) == toupper(team_class[i].abr[0]) && toupper(text[1]) == toupper(team_class[i].abr[1]) ) return ( ++i ); } return ( 0 ); } #ifdef DISPLAY_STRUCTURES /*============================================================================ ** ** Display structure information ** ** Purpose: Display internal structure information ** ** Parameters: Nothing ** ** Returns: Nothing directly ** **===========================================================================*/ /* ** esize - A macro to return the size of a structure element ** element - print element information */ #define esize( st, el) ( sizeof(((st *)0)->el)) #define element( st, el) \ printf( "Offset of %-15s :%4d, Size:%d", #el, offsetof( st, el), esize(st, el) ); #define element2( st, el) \ printf( "Size of %-15s :%4d", #el, esize(st, el) ); void display_structures(void) { printf( "Structure: leg_type" ); element( leg_type, start ); element( leg_type, end ); element( leg_type, elapsed ); element( leg_type, l_place ); element( leg_type, le_place ); element( leg_type, lc_place ); element( leg_type, lec_place); element( leg_type, manual ); printf( "Sizeof %-18s :%4d", "leg_type", sizeof(leg_type) ); printf( "" ); printf( "Structure: team_type" ); element( team_type, numb ); element( team_type, name ); element( team_type, leg ); element( team_type, members); element( team_type, teamclass ); element( team_type, country); element( team_type, flags ); printf( "Sizeof %-18s :%4d", "team_type", sizeof(team_type) ); #if 1 printf( "" ); printf( "Structure: MARA_CFG" ); element2( QmConfig, event_name ); element2( QmConfig, leg_name ); element2( QmConfig, t_def ); element2( QmConfig, num_legs ); element2( QmConfig, num_teams ); element2( QmConfig, max_team ); element2( QmConfig, min_team ); element2( QmConfig, team_class ); element2( QmConfig, num_class ); element2( QmConfig, country_name ); element2( QmConfig, num_countries ); element2( QmConfig, addendum ); element2( QmConfig, datafilename ); printf( "Sizeof %-18s :%4d", "QmConfig", sizeof(QmConfig) ); #endif } #endif