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