OptionFile.cpp

Go to the documentation of this file.
00001 /**
00002 \file    OptionFile.cpp
00003 \brief   A class for handling option files. 
00004          ';' delimits a comment to follow. \n
00005          The general format is: \n
00006          field, comment = value ; comment \n
00007          e.g. \n
00008          ; A data value will follow this comment \n
00009          DataValue, (some comment about it) = 88 ; another comment here \n
00010 
00011 \author  Glenn D. MacGougan (GDM)
00012 \date    2007-11-28
00013 \since   2006-12-07
00014 
00015 \b "LICENSE INFORMATION" \n
00016 Copyright (c) 2007, refer to 'author' doxygen tags \n
00017 All rights reserved. \n
00018 
00019 Redistribution and use in source and binary forms, with or without
00020 modification, are permitted provided the following conditions are met: \n
00021 
00022 - Redistributions of source code must retain the above copyright
00023   notice, this list of conditions and the following disclaimer. \n
00024 - Redistributions in binary form must reproduce the above copyright
00025   notice, this list of conditions and the following disclaimer in the
00026   documentation and/or other materials provided with the distribution. \n
00027 - The name(s) of the contributor(s) may not be used to endorse or promote 
00028   products derived from this software without specific prior written 
00029   permission. \n
00030 
00031 THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 
00032 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00033 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00034 DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00035 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00036 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00037 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00038 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00039 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00040 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00041 SUCH DAMAGE.
00042 */
00043 
00044 #include <stdio.h>
00045 #include <ctype.h>
00046 #include "OptionFile.h"
00047 #include "StdStringUtils.h"
00048 
00049 #define OPTIONFILE_MAX_LINES (8192)
00050 #define OPTIONFILE_MAX_LINE_BUFFER (8192)
00051 
00052 //#define _CRT_SECURE_NO_DEPRECATE
00053 
00054 
00055 OptionFile::~OptionFile()
00056 {
00057   if( m_Options != NULL )
00058     delete [] m_Options;
00059   m_nrOptions = 0;
00060   m_OptionFilePathUsed.erase();
00061 }
00062 
00063 
00064 OptionFile::OptionFile()
00065 : m_Options(NULL),
00066   m_nrOptions(0)
00067 {     
00068 }
00069 
00070 bool OptionFile::ReadOptionFile( const std::string OptionFilePath )
00071 {
00072   unsigned i = 0;
00073   unsigned j = 0;
00074   unsigned numLines = 0;
00075   std::string::size_type p = 0;
00076   std::string::size_type equalsIndex = 0;
00077   bool result = false;
00078   FILE *fid = NULL;
00079   char lineBuffer[OPTIONFILE_MAX_LINE_BUFFER];
00080   char* fgetsBuffer = NULL;
00081   std::string DataLine;
00082   std::string TmpStr;
00083   std::string FieldAndComment;
00084   std::string Value;
00085 
00086   // test that the path is set
00087   if( OptionFilePath.empty() )
00088   {
00089     return false;
00090   }
00091 
00092   // test if the file exists
00093   if( DoesFileExist( OptionFilePath ) == false )
00094   {
00095     return false;
00096   }
00097 
00098   // open the input file
00099 #ifndef _CRT_SECURE_NO_DEPRECATE
00100   if( fopen_s( &fid, OptionFilePath.c_str(), "r" ) != 0 )
00101   {
00102     return false;
00103   }
00104 #else
00105   fid = fopen( OptionFilePath.c_str(), "r" );
00106 #endif
00107   if( fid == NULL )
00108   {
00109     return false;
00110   }
00111 
00112   m_OptionFilePathUsed = OptionFilePath;
00113 
00114   // count the number of lines in the file up to a maximum line count
00115   for( i = 0; i < OPTIONFILE_MAX_LINES; i++ )
00116   {
00117     fgetsBuffer = fgets( lineBuffer, OPTIONFILE_MAX_LINE_BUFFER, fid );
00118     if( fgetsBuffer == NULL )
00119     {
00120       break;
00121     }
00122   }
00123   numLines = i;
00124 
00125   // allocate enough option structs to hold all the option data
00126   m_Options = new stOption[numLines];
00127   if( m_Options == NULL )
00128   {
00129     return false;
00130   }
00131 
00132   // read in the option file information
00133   rewind( fid );
00134   for( i = 0; i < numLines; i++ )
00135   {
00136     // initialize strings
00137     m_Options[j].Field.erase();
00138     m_Options[j].Comment.erase();
00139     m_Options[j].Value.erase();
00140     m_Options[j].PostValueComment.erase();
00141 
00142     fgetsBuffer = fgets( lineBuffer, OPTIONFILE_MAX_LINE_BUFFER, fid );
00143     if( fgetsBuffer == NULL )
00144     {
00145       break;
00146     }
00147 
00148     DataLine = lineBuffer;
00149     StdStringUtils::TrimLeftAndRight( DataLine ); // get rid of whitespace
00150 
00151     // check for empty line
00152     if( DataLine.empty() )
00153     {
00154       continue;
00155     }
00156 
00157     // is this line a pure comment line
00158     if( DataLine[0] == ';' )
00159     {
00160       continue; // then just skip this line
00161     }
00162 
00163     // check that this line contains
00164     // <field> = <value> // at a minimum
00165     equalsIndex = DataLine.rfind( "=" );
00166     if( equalsIndex == std::string::npos )
00167     {
00168       continue; // invalid line
00169     }
00170 
00171     // check that there is a data <field>
00172     FieldAndComment = DataLine.substr( 0, equalsIndex );
00173     if( equalsIndex+1 < DataLine.length() )
00174       DataLine = DataLine.substr( equalsIndex+1 );
00175     else
00176       DataLine.erase();
00177 
00178     StdStringUtils::TrimLeftAndRight( DataLine );
00179     StdStringUtils::TrimLeftAndRight( FieldAndComment );
00180     if( FieldAndComment.empty() ) 
00181     {
00182       continue; // no <field>, invalid line
00183     }
00184 
00185     // check if there is a comment in the Field component
00186     p = FieldAndComment.find( "," );
00187     if( p != std::string::npos )
00188     {
00189       // get the data <field>
00190       result = StdStringUtils::ExtractFieldInplace( FieldAndComment, ',', m_Options[j].Field );
00191       if( result == false )
00192       {
00193         continue; // invalid line
00194       }
00195       StdStringUtils::TrimLeftAndRight( m_Options[j].Field );
00196       if( m_Options[j].Field.empty() )
00197       {
00198         continue; // invalid line (only a comment present)
00199       }
00200 
00201       m_Options[j].Comment = FieldAndComment;
00202       StdStringUtils::TrimLeftAndRight( m_Options[j].Comment ); // comment can be empty
00203     }
00204     else
00205     {
00206       m_Options[j].Field = FieldAndComment;
00207       m_Options[j].Comment.erase();
00208     }
00209 
00210     // get the value string with a post value comment if any
00211     Value.erase();
00212     Value = DataLine;
00213 
00214     if( Value.empty() )
00215     {
00216       m_Options[j].Value = Value;
00217       m_Options[j].PostValueComment.erase();
00218       j++;
00219       continue;
00220     }
00221 
00222     // check if there is a comment
00223     p = Value.find( ";" );
00224     if( p != std::string::npos )
00225     {
00226       result = StdStringUtils::ExtractFieldInplace( Value, ';', m_Options[j].Value );
00227       StdStringUtils::TrimLeftAndRight( m_Options[j].Value );
00228       m_Options[j].PostValueComment = Value;
00229       StdStringUtils::TrimLeftAndRight( m_Options[j].PostValueComment );
00230       j++;
00231     }
00232     else
00233     {
00234       m_Options[j].Value = Value;
00235       m_Options[j].PostValueComment.erase();
00236       j++;
00237     }
00238   }
00239 
00240   fclose( fid );
00241 
00242   m_nrOptions = j;
00243 
00244   return true;
00245 }
00246 
00247 bool OptionFile::DoesFileExist( const std::string& OptionFilePath )
00248 {
00249   FILE *fid = NULL;
00250 
00251 #ifndef _CRT_SECURE_NO_DEPRECATE
00252   if( fopen_s( &fid, OptionFilePath.c_str(), "r" ) != 0 )
00253   {
00254     return false;
00255   }
00256 #else
00257   fid = fopen( OptionFilePath.c_str(), "r" );
00258 #endif
00259   if( fid == NULL )
00260   {
00261     return false;
00262   }
00263   else
00264   {
00265     fclose( fid );
00266     return true;
00267   }
00268 }
00269 
00270 bool OptionFile::GetValue( const std::string Field, std::string &Value )
00271 {
00272   std::string Comment;
00273   std::string PostValueComment;
00274   if( FindField( Field, Comment, Value, PostValueComment ) )
00275   {
00276     return true;
00277   }
00278   else
00279   {
00280     return false;
00281   }
00282 }
00283 
00284 bool OptionFile::GetValue( const std::string Field, double &value )
00285 {
00286   std::string Comment;
00287   std::string Value;
00288   std::string PostValueComment;
00289   if( FindField( Field, Comment, Value, PostValueComment ) )
00290   {
00291     if( StdStringUtils::GetDouble( Value, value ) )
00292       return true;
00293     else
00294       return false;
00295   }
00296   else
00297   {
00298     return false;
00299   }
00300 }
00301 
00302 bool OptionFile::GetValue( const std::string Field, float  &value )
00303 {
00304   std::string Comment;
00305   std::string Value;
00306   std::string PostValueComment;
00307   if( FindField( Field, Comment, Value, PostValueComment ) )
00308   {
00309     if( StdStringUtils::GetFloat( Value, value ) )
00310       return true;
00311     else
00312       return false;
00313   }
00314   else
00315   {
00316     return false;
00317   }
00318 }
00319 
00320 bool OptionFile::GetValue( const std::string Field, short  &value )
00321 {
00322   int tmp = 0;
00323   std::string Comment;
00324   std::string Value;
00325   std::string PostValueComment;
00326   if( FindField( Field, Comment, Value, PostValueComment ) )
00327   {
00328     if( StdStringUtils::GetInt( Value, tmp ) )
00329     {
00330       value = (short) tmp;
00331       return true;
00332     }
00333     else
00334     {
00335       return false;
00336     }
00337   }
00338   else
00339   {
00340     return false;
00341   }
00342 }
00343 
00344 bool OptionFile::GetValue( const std::string Field, unsigned short &value )
00345 {
00346   unsigned int tmp = 0;
00347   std::string Comment;
00348   std::string Value;
00349   std::string PostValueComment;
00350   if( FindField( Field, Comment, Value, PostValueComment ) )
00351   {
00352     if( StdStringUtils::GetUnsignedInt( Value, tmp ) )
00353     {
00354       value = (unsigned short) tmp;
00355       return true;
00356     }
00357     else
00358     {
00359       return false;
00360     }
00361   }
00362   else
00363   {
00364     return false;
00365   }
00366 }
00367 
00368 
00369 bool OptionFile::GetValue( const std::string Field, int &value )
00370 {
00371   std::string Comment;
00372   std::string Value;
00373   std::string PostValueComment;
00374   if( FindField( Field, Comment, Value, PostValueComment ) )
00375   {
00376     if( StdStringUtils::GetInt( Value, value ) )
00377     {
00378       return true;
00379     }
00380     else
00381     {
00382       return false;
00383     }
00384   }
00385   else
00386   {
00387     return false;
00388   }
00389 }
00390 
00391 bool OptionFile::GetValue( const std::string Field, unsigned int &value )
00392 {
00393   std::string Comment;
00394   std::string Value;
00395   std::string PostValueComment;
00396   if( FindField( Field, Comment, Value, PostValueComment ) )
00397   {
00398     if( StdStringUtils::GetUnsignedInt( Value, value ) )
00399     {
00400       return true;
00401     }
00402     else
00403     {
00404       return false;
00405     }
00406   }
00407   else
00408   {
00409     return false;
00410   }
00411 }
00412 
00413 
00414 bool OptionFile::GetValue( const std::string Field, bool &value )
00415 {
00416   int iTmp = 0;
00417   char ch = 0;
00418   std::string Comment;
00419   std::string Value;
00420   std::string PostValueComment;
00421   if( FindField( Field, Comment, Value, PostValueComment ) )
00422   {
00423     ch = Value[0];
00424     if( isdigit( ch ) )
00425     {
00426       if( StdStringUtils::GetInt( Value, iTmp ) )
00427       {
00428         if( iTmp == 0 )
00429         {
00430           value = false;
00431         }
00432         else
00433         {
00434           value = true;
00435         }
00436       }
00437       else
00438       {
00439         value = false;
00440         return false;
00441       }
00442     }
00443     else
00444     {
00445       ch = toupper( ch );
00446       if( ch == 'Y' )
00447       {
00448         if( Value.length() > 1 )
00449         {
00450           StdStringUtils::MakeUpper( Value );
00451           if( Value == "YES" )
00452           {
00453             value = true;
00454           }
00455           else
00456           {
00457             value = false;
00458           }
00459         }
00460         else
00461         {
00462           value = true;
00463         }
00464       }
00465       else
00466       {
00467         value = false;
00468       }
00469     }
00470     return true;
00471   }
00472   else
00473   {
00474     return false;
00475   }
00476 }
00477 
00478 
00479 bool OptionFile::GetValueArray( 
00480   const std::string Field,      //!< The field identifier
00481   int *intArray,           //!< The pointer to the integer array.
00482   const unsigned maxItems, //!< The maximum number of elements in the array.
00483   unsigned &nrItems        //!< The number of valid items read into the array.
00484   )
00485 {
00486   unsigned i = 0;
00487   unsigned n = 0; // number of valid items read
00488   std::string Comment;
00489   std::string Value;
00490   std::string PostValueComment;
00491   std::string SingleInt;
00492   std::string::size_type p = 0;
00493 
00494   if( intArray == NULL )
00495     return false;
00496 
00497   nrItems = 0;
00498   if( FindField( Field, Comment, Value, PostValueComment ) )
00499   {
00500     for( i = 0; i < maxItems; i++ )
00501     {
00502       if( Value.empty() )
00503         break;
00504 
00505       // check for ',' as a delimiter
00506       p = Value.find( "," );
00507       if( p != std::string::npos )
00508       {
00509         if( StdStringUtils::ExtractFieldInplace( Value, ',', SingleInt ) == false )
00510           return false;
00511       }
00512       else
00513       {
00514         if( StdStringUtils::ExtractFieldInplace( Value, 'w', SingleInt ) == false )
00515           return false;
00516       }
00517 
00518       if( SingleInt.empty() )
00519         break;
00520 
00521       if( StdStringUtils::GetInt( SingleInt, intArray[i] ) == false )
00522         return false;
00523 
00524       n++;
00525     }
00526   }
00527   else
00528   {
00529     return false;
00530   }
00531 
00532   nrItems = n;
00533 
00534   return true;
00535 }
00536 
00537 
00538 bool OptionFile::GetValueArray( 
00539   const std::string Field, //!< The field identifier
00540   double *dArray,          //!< The pointer to the integer array.
00541   const unsigned maxItems, //!< The maximum number of elements in the array.
00542   unsigned &nrItems        //!< The number of valid items read into the array.
00543   )
00544 {
00545   unsigned i = 0;
00546   unsigned n = 0; // number of valid items read
00547   std::string Comment;
00548   std::string Value;
00549   std::string PostValueComment;
00550   std::string SingleDouble;
00551   std::string::size_type p = 0;
00552 
00553   if( dArray == NULL )
00554     return false;
00555 
00556   nrItems = 0;
00557   if( FindField( Field, Comment, Value, PostValueComment ) )
00558   {
00559     for( i = 0; i < maxItems; i++ )
00560     {
00561       if( Value.empty() )
00562         break;
00563 
00564       // check for ',' as a delimiter
00565       p = Value.find( "," );
00566       if( p != std::string::npos )
00567       {
00568         if( StdStringUtils::ExtractFieldInplace( Value, ',', SingleDouble ) == false )
00569           return false;
00570       }
00571       else
00572       {
00573         if( StdStringUtils::ExtractFieldInplace( Value, 'w', SingleDouble ) == false )
00574           return false;
00575       }
00576 
00577       if( SingleDouble.empty() )
00578         break;
00579 
00580       if( StdStringUtils::GetDouble( SingleDouble, dArray[i] ) == false )
00581         return false;
00582 
00583       n++;
00584     }
00585   }
00586   else
00587   {
00588     return false;
00589   }
00590 
00591   nrItems = n;
00592 
00593   return true;
00594 }
00595 
00596 
00597 
00598 bool OptionFile::GetComment( const std::string Field, std::string &Comment )
00599 {
00600   std::string Value;
00601   std::string PostValueComment;
00602   if( FindField( Field, Comment, Value, PostValueComment ) )
00603   {
00604     return true;
00605   }
00606   else
00607   {
00608     return false;
00609   }
00610 }
00611 
00612 bool OptionFile::GetPostValueComment( const std::string Field, std::string &PostValueComment )
00613 {
00614   std::string Value;
00615   std::string Comment;
00616   if( FindField( Field, Comment, Value, PostValueComment ) )
00617   {
00618     return true;
00619   }
00620   else
00621   {
00622     return false;
00623   }
00624 }
00625 
00626 
00627 bool OptionFile::GetDMSValue( const std::string Field, double &value )
00628 {
00629   std::string Value;
00630   std::string Comment;
00631   std::string PostValueComment;
00632   std::string TmpStr;
00633   int degrees = 0;
00634   int minutes = 0;
00635   double seconds = 0;
00636   if( FindField( Field, Comment, Value, PostValueComment ) )
00637   {
00638     if( StdStringUtils::ExtractFieldInplace( Value, 'w', TmpStr ) == false )
00639       return false;
00640     if( StdStringUtils::GetInt( TmpStr, degrees ) == false )
00641       return false;
00642     if( StdStringUtils::ExtractFieldInplace( Value, 'w', TmpStr ) == false )
00643       return false;
00644     if( StdStringUtils::GetInt( TmpStr, minutes ) == false )
00645       return false;
00646     if( minutes < 0 )
00647       return false;
00648 
00649     if( StdStringUtils::GetDouble( Value, seconds ) == false )    
00650       return false;
00651 
00652     if( degrees < 0 )
00653       value = degrees - minutes/60.0 + seconds/3600.0;
00654     else
00655       value = degrees + minutes/60.0 + seconds/3600.0;
00656 
00657     return true;
00658   }
00659   else
00660   {
00661     return false;
00662   }
00663 }
00664 
00665 
00666 
00667 bool OptionFile::FindField( 
00668   const std::string &Field, 
00669   std::string &Comment,
00670   std::string &Value,
00671   std::string &PostValueComment )
00672 {
00673   unsigned i = 0;
00674   std::string UpperCaseFieldToFind;
00675   std::string UpperCaseField;
00676 
00677   // initial string to empty
00678   Comment.erase();
00679   Value.erase();
00680   PostValueComment.erase();
00681 
00682   // convert the search string to upper case and trim it
00683   UpperCaseFieldToFind = Field;
00684   StdStringUtils::TrimLeftAndRight( UpperCaseFieldToFind );
00685 
00686   if( UpperCaseFieldToFind.empty() )
00687     return false;
00688 
00689   StdStringUtils::MakeUpper( UpperCaseFieldToFind );
00690 
00691   // search the stored fields
00692   for( i = 0; i < m_nrOptions; i++ )
00693   {
00694     UpperCaseField = m_Options[i].Field;
00695     StdStringUtils::MakeUpper( UpperCaseField );
00696 
00697     if( UpperCaseFieldToFind == UpperCaseField )
00698     {
00699       Comment = m_Options[i].Comment;
00700       Value = m_Options[i].Value;
00701       PostValueComment = m_Options[i].PostValueComment;
00702       return true;
00703     }
00704   }
00705 
00706   return false;
00707 }
00708 
00709