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 #ifndef _CRT_SECURE_NO_DEPRECATE
00053 #define _CRT_SECURE_NO_DEPRECATE
00054 #endif
00055 
00056 
00057 
00058 OptionFile::~OptionFile()
00059 {
00060   if( m_Options != NULL )
00061     delete [] m_Options;
00062   m_nrOptions = 0;
00063   m_OptionFilePathUsed.erase();
00064 }
00065 
00066 
00067 OptionFile::OptionFile()
00068 : m_Options(NULL),
00069   m_nrOptions(0)
00070 {     
00071 }
00072 
00073 bool OptionFile::ReadOptionFile( const std::string OptionFilePath )
00074 {
00075   unsigned i = 0;
00076   unsigned j = 0;
00077   unsigned numLines = 0;
00078   std::string::size_type p = 0;
00079   std::string::size_type equalsIndex = 0;
00080   bool result = false;
00081   FILE *fid = NULL;
00082   char lineBuffer[OPTIONFILE_MAX_LINE_BUFFER];
00083   char* fgetsBuffer = NULL;
00084   std::string DataLine;
00085   std::string TmpStr;
00086   std::string FieldAndComment;
00087   std::string Value;
00088 
00089   // test that the path is set
00090   if( OptionFilePath.empty() )
00091   {
00092     return false;
00093   }
00094 
00095   // test if the file exists
00096   if( DoesFileExist( OptionFilePath ) == false )
00097   {
00098     return false;
00099   }
00100 
00101   // open the input file
00102 #ifndef _CRT_SECURE_NO_DEPRECATE
00103   if( fopen_s( &fid, OptionFilePath.c_str(), "r" ) != 0 )
00104   {
00105     return false;
00106   }
00107 #else
00108   fid = fopen( OptionFilePath.c_str(), "r" );
00109 #endif
00110   if( fid == NULL )
00111   {
00112     return false;
00113   }
00114 
00115   m_OptionFilePathUsed = OptionFilePath;
00116 
00117   // count the number of lines in the file up to a maximum line count
00118   for( i = 0; i < OPTIONFILE_MAX_LINES; i++ )
00119   {
00120     fgetsBuffer = fgets( lineBuffer, OPTIONFILE_MAX_LINE_BUFFER, fid );
00121     if( fgetsBuffer == NULL )
00122     {
00123       break;
00124     }
00125   }
00126   numLines = i;
00127 
00128   // allocate enough option structs to hold all the option data
00129   m_Options = new stOption[numLines];
00130   if( m_Options == NULL )
00131   {
00132     return false;
00133   }
00134 
00135   // read in the option file information
00136   rewind( fid );
00137   for( i = 0; i < numLines; i++ )
00138   {
00139     // initialize strings
00140     m_Options[j].Field.erase();
00141     m_Options[j].Comment.erase();
00142     m_Options[j].Value.erase();
00143     m_Options[j].PostValueComment.erase();
00144 
00145     fgetsBuffer = fgets( lineBuffer, OPTIONFILE_MAX_LINE_BUFFER, fid );
00146     if( fgetsBuffer == NULL )
00147     {
00148       break;
00149     }
00150 
00151     DataLine = lineBuffer;
00152     StdStringUtils::TrimLeftAndRight( DataLine ); // get rid of whitespace
00153 
00154     // check for empty line
00155     if( DataLine.empty() )
00156     {
00157       continue;
00158     }
00159 
00160     // is this line a pure comment line
00161     if( DataLine[0] == ';' )
00162     {
00163       continue; // then just skip this line
00164     }
00165 
00166     // check that this line contains
00167     // <field> = <value> // at a minimum
00168     equalsIndex = DataLine.rfind( "=" );
00169     if( equalsIndex == std::string::npos )
00170     {
00171       continue; // invalid line
00172     }
00173 
00174     // check that there is a data <field>
00175     FieldAndComment = DataLine.substr( 0, equalsIndex );
00176     if( equalsIndex+1 < DataLine.length() )
00177       DataLine = DataLine.substr( equalsIndex+1 );
00178     else
00179       DataLine.erase();
00180 
00181     StdStringUtils::TrimLeftAndRight( DataLine );
00182     StdStringUtils::TrimLeftAndRight( FieldAndComment );
00183     if( FieldAndComment.empty() ) 
00184     {
00185       continue; // no <field>, invalid line
00186     }
00187 
00188     // check if there is a comment in the Field component
00189     p = FieldAndComment.find( "," );
00190     if( p != std::string::npos )
00191     {
00192       // get the data <field>
00193       result = StdStringUtils::ExtractFieldInplace( FieldAndComment, ',', m_Options[j].Field );
00194       if( result == false )
00195       {
00196         continue; // invalid line
00197       }
00198       StdStringUtils::TrimLeftAndRight( m_Options[j].Field );
00199       if( m_Options[j].Field.empty() )
00200       {
00201         continue; // invalid line (only a comment present)
00202       }
00203 
00204       m_Options[j].Comment = FieldAndComment;
00205       StdStringUtils::TrimLeftAndRight( m_Options[j].Comment ); // comment can be empty
00206     }
00207     else
00208     {
00209       m_Options[j].Field = FieldAndComment;
00210       m_Options[j].Comment.erase();
00211     }
00212 
00213     // get the value string with a post value comment if any
00214     Value.erase();
00215     Value = DataLine;
00216 
00217     if( Value.empty() )
00218     {
00219       m_Options[j].Value = Value;
00220       m_Options[j].PostValueComment.erase();
00221       j++;
00222       continue;
00223     }
00224 
00225     // check if there is a comment
00226     p = Value.find( ";" );
00227     if( p != std::string::npos )
00228     {
00229       result = StdStringUtils::ExtractFieldInplace( Value, ';', m_Options[j].Value );
00230       StdStringUtils::TrimLeftAndRight( m_Options[j].Value );
00231       m_Options[j].PostValueComment = Value;
00232       StdStringUtils::TrimLeftAndRight( m_Options[j].PostValueComment );
00233       j++;
00234     }
00235     else
00236     {
00237       m_Options[j].Value = Value;
00238       m_Options[j].PostValueComment.erase();
00239       j++;
00240     }
00241   }
00242 
00243   fclose( fid );
00244 
00245   m_nrOptions = j;
00246 
00247   return true;
00248 }
00249 
00250 bool OptionFile::DoesFileExist( const std::string& OptionFilePath )
00251 {
00252   FILE *fid = NULL;
00253 
00254 #ifndef _CRT_SECURE_NO_DEPRECATE
00255   if( fopen_s( &fid, OptionFilePath.c_str(), "r" ) != 0 )
00256   {
00257     return false;
00258   }
00259 #else
00260   fid = fopen( OptionFilePath.c_str(), "r" );
00261 #endif
00262   if( fid == NULL )
00263   {
00264     return false;
00265   }
00266   else
00267   {
00268     fclose( fid );
00269     return true;
00270   }
00271 }
00272 
00273 bool OptionFile::GetValue( const std::string Field, std::string &Value )
00274 {
00275   std::string Comment;
00276   std::string PostValueComment;
00277   if( FindField( Field, Comment, Value, PostValueComment ) )
00278   {
00279     return true;
00280   }
00281   else
00282   {
00283     return false;
00284   }
00285 }
00286 
00287 bool OptionFile::GetValue( const std::string Field, double &value )
00288 {
00289   std::string Comment;
00290   std::string Value;
00291   std::string PostValueComment;
00292   if( FindField( Field, Comment, Value, PostValueComment ) )
00293   {
00294     if( StdStringUtils::GetDouble( Value, value ) )
00295       return true;
00296     else
00297       return false;
00298   }
00299   else
00300   {
00301     return false;
00302   }
00303 }
00304 
00305 bool OptionFile::GetValue( const std::string Field, float  &value )
00306 {
00307   std::string Comment;
00308   std::string Value;
00309   std::string PostValueComment;
00310   if( FindField( Field, Comment, Value, PostValueComment ) )
00311   {
00312     if( StdStringUtils::GetFloat( Value, value ) )
00313       return true;
00314     else
00315       return false;
00316   }
00317   else
00318   {
00319     return false;
00320   }
00321 }
00322 
00323 bool OptionFile::GetValue( const std::string Field, short  &value )
00324 {
00325   int tmp = 0;
00326   std::string Comment;
00327   std::string Value;
00328   std::string PostValueComment;
00329   if( FindField( Field, Comment, Value, PostValueComment ) )
00330   {
00331     if( StdStringUtils::GetInt( Value, tmp ) )
00332     {
00333       value = (short) tmp;
00334       return true;
00335     }
00336     else
00337     {
00338       return false;
00339     }
00340   }
00341   else
00342   {
00343     return false;
00344   }
00345 }
00346 
00347 bool OptionFile::GetValue( const std::string Field, unsigned short &value )
00348 {
00349   unsigned int tmp = 0;
00350   std::string Comment;
00351   std::string Value;
00352   std::string PostValueComment;
00353   if( FindField( Field, Comment, Value, PostValueComment ) )
00354   {
00355     if( StdStringUtils::GetUnsignedInt( Value, tmp ) )
00356     {
00357       value = (unsigned short) tmp;
00358       return true;
00359     }
00360     else
00361     {
00362       return false;
00363     }
00364   }
00365   else
00366   {
00367     return false;
00368   }
00369 }
00370 
00371 
00372 bool OptionFile::GetValue( const std::string Field, int &value )
00373 {
00374   std::string Comment;
00375   std::string Value;
00376   std::string PostValueComment;
00377   if( FindField( Field, Comment, Value, PostValueComment ) )
00378   {
00379     if( StdStringUtils::GetInt( Value, value ) )
00380     {
00381       return true;
00382     }
00383     else
00384     {
00385       return false;
00386     }
00387   }
00388   else
00389   {
00390     return false;
00391   }
00392 }
00393 
00394 bool OptionFile::GetValue( const std::string Field, unsigned int &value )
00395 {
00396   std::string Comment;
00397   std::string Value;
00398   std::string PostValueComment;
00399   if( FindField( Field, Comment, Value, PostValueComment ) )
00400   {
00401     if( StdStringUtils::GetUnsignedInt( Value, value ) )
00402     {
00403       return true;
00404     }
00405     else
00406     {
00407       return false;
00408     }
00409   }
00410   else
00411   {
00412     return false;
00413   }
00414 }
00415 
00416 
00417 bool OptionFile::GetValue( const std::string Field, bool &value )
00418 {
00419   int iTmp = 0;
00420   char ch = 0;
00421   std::string Comment;
00422   std::string Value;
00423   std::string PostValueComment;
00424   if( FindField( Field, Comment, Value, PostValueComment ) )
00425   {
00426     ch = Value[0];
00427     if( isdigit( ch ) )
00428     {
00429       if( StdStringUtils::GetInt( Value, iTmp ) )
00430       {
00431         if( iTmp == 0 )
00432         {
00433           value = false;
00434         }
00435         else
00436         {
00437           value = true;
00438         }
00439       }
00440       else
00441       {
00442         value = false;
00443         return false;
00444       }
00445     }
00446     else
00447     {
00448       ch = toupper( ch );
00449       if( ch == 'Y' )
00450       {
00451         if( Value.length() > 1 )
00452         {
00453           StdStringUtils::MakeUpper( Value );
00454           if( Value == "YES" )
00455           {
00456             value = true;
00457           }
00458           else
00459           {
00460             value = false;
00461           }
00462         }
00463         else
00464         {
00465           value = true;
00466         }
00467       }
00468       else
00469       {
00470         value = false;
00471       }
00472     }
00473     return true;
00474   }
00475   else
00476   {
00477     return false;
00478   }
00479 }
00480 
00481 
00482 bool OptionFile::GetValueArray( 
00483   const std::string Field,      //!< The field identifier
00484   int *intArray,           //!< The pointer to the integer array.
00485   const unsigned maxItems, //!< The maximum number of elements in the array.
00486   unsigned &nrItems        //!< The number of valid items read into the array.
00487   )
00488 {
00489   unsigned i = 0;
00490   unsigned n = 0; // number of valid items read
00491   std::string Comment;
00492   std::string Value;
00493   std::string PostValueComment;
00494   std::string SingleInt;
00495   std::string::size_type p = 0;
00496 
00497   if( intArray == NULL )
00498     return false;
00499 
00500   nrItems = 0;
00501   if( FindField( Field, Comment, Value, PostValueComment ) )
00502   {
00503     for( i = 0; i < maxItems; i++ )
00504     {
00505       if( Value.empty() )
00506         break;
00507 
00508       // check for ',' as a delimiter
00509       p = Value.find( "," );
00510       if( p != std::string::npos )
00511       {
00512         if( StdStringUtils::ExtractFieldInplace( Value, ',', SingleInt ) == false )
00513           return false;
00514       }
00515       else
00516       {
00517         if( StdStringUtils::ExtractFieldInplace( Value, 'w', SingleInt ) == false )
00518           return false;
00519       }
00520 
00521       if( SingleInt.empty() )
00522         break;
00523 
00524       if( StdStringUtils::GetInt( SingleInt, intArray[i] ) == false )
00525         return false;
00526 
00527       n++;
00528     }
00529   }
00530   else
00531   {
00532     return false;
00533   }
00534 
00535   nrItems = n;
00536 
00537   return true;
00538 }
00539 
00540 
00541 bool OptionFile::GetValueArray( 
00542   const std::string Field, //!< The field identifier
00543   double *dArray,          //!< The pointer to the integer array.
00544   const unsigned maxItems, //!< The maximum number of elements in the array.
00545   unsigned &nrItems        //!< The number of valid items read into the array.
00546   )
00547 {
00548   unsigned i = 0;
00549   unsigned n = 0; // number of valid items read
00550   std::string Comment;
00551   std::string Value;
00552   std::string PostValueComment;
00553   std::string SingleDouble;
00554   std::string::size_type p = 0;
00555 
00556   if( dArray == NULL )
00557     return false;
00558 
00559   nrItems = 0;
00560   if( FindField( Field, Comment, Value, PostValueComment ) )
00561   {
00562     for( i = 0; i < maxItems; i++ )
00563     {
00564       if( Value.empty() )
00565         break;
00566 
00567       // check for ',' as a delimiter
00568       p = Value.find( "," );
00569       if( p != std::string::npos )
00570       {
00571         if( StdStringUtils::ExtractFieldInplace( Value, ',', SingleDouble ) == false )
00572           return false;
00573       }
00574       else
00575       {
00576         if( StdStringUtils::ExtractFieldInplace( Value, 'w', SingleDouble ) == false )
00577           return false;
00578       }
00579 
00580       if( SingleDouble.empty() )
00581         break;
00582 
00583       if( StdStringUtils::GetDouble( SingleDouble, dArray[i] ) == false )
00584         return false;
00585 
00586       n++;
00587     }
00588   }
00589   else
00590   {
00591     return false;
00592   }
00593 
00594   nrItems = n;
00595 
00596   return true;
00597 }
00598 
00599 
00600 
00601 bool OptionFile::GetComment( const std::string Field, std::string &Comment )
00602 {
00603   std::string Value;
00604   std::string PostValueComment;
00605   if( FindField( Field, Comment, Value, PostValueComment ) )
00606   {
00607     return true;
00608   }
00609   else
00610   {
00611     return false;
00612   }
00613 }
00614 
00615 bool OptionFile::GetPostValueComment( const std::string Field, std::string &PostValueComment )
00616 {
00617   std::string Value;
00618   std::string Comment;
00619   if( FindField( Field, Comment, Value, PostValueComment ) )
00620   {
00621     return true;
00622   }
00623   else
00624   {
00625     return false;
00626   }
00627 }
00628 
00629 
00630 bool OptionFile::GetDMSValue( const std::string Field, double &value )
00631 {
00632   std::string Value;
00633   std::string Comment;
00634   std::string PostValueComment;
00635   std::string TmpStr;
00636   int degrees = 0;
00637   int minutes = 0;
00638   double seconds = 0;
00639   if( FindField( Field, Comment, Value, PostValueComment ) )
00640   {
00641     if( StdStringUtils::ExtractFieldInplace( Value, 'w', TmpStr ) == false )
00642       return false;
00643     if( StdStringUtils::GetInt( TmpStr, degrees ) == false )
00644       return false;
00645     if( StdStringUtils::ExtractFieldInplace( Value, 'w', TmpStr ) == false )
00646       return false;
00647     if( StdStringUtils::GetInt( TmpStr, minutes ) == false )
00648       return false;
00649     if( minutes < 0 )
00650       return false;
00651 
00652     if( StdStringUtils::GetDouble( Value, seconds ) == false )    
00653       return false;
00654 
00655     if( degrees < 0 )
00656       value = degrees - minutes/60.0 + seconds/3600.0;
00657     else
00658       value = degrees + minutes/60.0 + seconds/3600.0;
00659 
00660     return true;
00661   }
00662   else
00663   {
00664     return false;
00665   }
00666 }
00667 
00668 
00669 
00670 bool OptionFile::FindField( 
00671   const std::string &Field, 
00672   std::string &Comment,
00673   std::string &Value,
00674   std::string &PostValueComment )
00675 {
00676   unsigned i = 0;
00677   std::string UpperCaseFieldToFind;
00678   std::string UpperCaseField;
00679 
00680   // initial string to empty
00681   Comment.erase();
00682   Value.erase();
00683   PostValueComment.erase();
00684 
00685   // convert the search string to upper case and trim it
00686   UpperCaseFieldToFind = Field;
00687   StdStringUtils::TrimLeftAndRight( UpperCaseFieldToFind );
00688 
00689   if( UpperCaseFieldToFind.empty() )
00690     return false;
00691 
00692   StdStringUtils::MakeUpper( UpperCaseFieldToFind );
00693 
00694   // search the stored fields
00695   for( i = 0; i < m_nrOptions; i++ )
00696   {
00697     UpperCaseField = m_Options[i].Field;
00698     StdStringUtils::MakeUpper( UpperCaseField );
00699 
00700     if( UpperCaseFieldToFind == UpperCaseField )
00701     {
00702       Comment = m_Options[i].Comment;
00703       Value = m_Options[i].Value;
00704       PostValueComment = m_Options[i].PostValueComment;
00705       return true;
00706     }
00707   }
00708 
00709   return false;
00710 }
00711 
00712