MOAB: Mesh Oriented datABase  (version 5.3.1)
FileOptions.cpp
Go to the documentation of this file.
00001 /*
00002  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
00003  * storing and accessing finite element mesh data.
00004  *
00005  * Copyright 2004 Sandia Corporation.  Under the terms of Contract
00006  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
00007  * retains certain rights in this software.
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  */
00015 
00016 /**\file FileOptions.cpp
00017  *\author Jason Kraftcheck (kraftche@cae.wisc.edu)
00018  *\date 2007-08-21
00019  */
00020 
00021 #include "moab/FileOptions.hpp"
00022 
00023 #include <cctype>
00024 #include <cstdlib>
00025 #include <cstring>
00026 #include <algorithm>
00027 
00028 namespace moab
00029 {
00030 
00031 const char DEFAULT_SEPARATOR = ';';
00032 
00033 static inline bool strempty( const char* s )
00034 {
00035     return !*s;
00036 }
00037 
00038 FileOptions::FileOptions( const char* str ) : mData( 0 )
00039 {
00040     // if option string is null, just return
00041     if( !str ) return;
00042 
00043     // check if alternate separator is specified
00044     char separator[2] = { DEFAULT_SEPARATOR, '\0' };
00045     if( *str == DEFAULT_SEPARATOR )
00046     {
00047         ++str;
00048         if( strempty( str ) ) return;
00049         separator[0] = *str;
00050         ++str;
00051     }
00052 
00053     // don't bother allocating copy of input string if
00054     // input string is empty.
00055     if( !strempty( str ) )
00056     {
00057         // tokenize at separator character
00058         mData = strdup( str );
00059         for( char* i = strtok( mData, separator ); i; i = strtok( 0, separator ) )
00060             if( !strempty( i ) )  // skip empty strings
00061                 mOptions.push_back( i );
00062     }
00063 
00064     mSeen.resize( mOptions.size(), false );
00065 }
00066 
00067 FileOptions::FileOptions( const FileOptions& copy ) : mData( 0 ), mOptions( copy.mOptions.size() )
00068 {
00069     if( !copy.mOptions.empty() )
00070     {
00071         const char* last   = copy.mOptions.back();
00072         const char* endptr = last + strlen( last ) + 1;
00073         size_t len         = endptr - copy.mData;
00074         mData              = (char*)malloc( len );
00075         memcpy( mData, copy.mData, len );
00076         for( size_t i = 0; i < mOptions.size(); ++i )
00077             mOptions[i] = mData + ( copy.mOptions[i] - copy.mData );
00078     }
00079     mSeen = copy.mSeen;
00080 }
00081 
00082 FileOptions& FileOptions::operator=( const FileOptions& copy )
00083 {
00084     // Check for self-assignment
00085     if( this == &copy ) return *this;
00086 
00087     free( mData );
00088     mData = 0;
00089     mOptions.resize( copy.mOptions.size() );
00090 
00091     if( !copy.mOptions.empty() )
00092     {
00093         const char* last   = copy.mOptions.back();
00094         const char* endptr = last + strlen( last ) + 1;
00095         size_t len         = endptr - copy.mData;
00096         mData              = (char*)malloc( len );
00097         memcpy( mData, copy.mData, len );
00098         for( size_t i = 0; i < mOptions.size(); ++i )
00099             mOptions[i] = mData + ( copy.mOptions[i] - copy.mData );
00100     }
00101 
00102     mSeen = copy.mSeen;
00103     return *this;
00104 }
00105 
00106 FileOptions::~FileOptions()
00107 {
00108     free( mData );
00109 }
00110 
00111 ErrorCode FileOptions::get_null_option( const char* name ) const
00112 {
00113     const char* s;
00114     ErrorCode rval = get_option( name, s );
00115     if( MB_SUCCESS != rval ) return rval;
00116     return strempty( s ) ? MB_SUCCESS : MB_TYPE_OUT_OF_RANGE;
00117 }
00118 
00119 ErrorCode FileOptions::get_int_option( const char* name, int& value ) const
00120 {
00121     const char* s;
00122     ErrorCode rval = get_option( name, s );
00123     if( MB_SUCCESS != rval ) return rval;
00124 
00125     // empty string
00126     if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
00127 
00128     // parse value
00129     char* endptr;
00130     long int pval = strtol( s, &endptr, 0 );
00131     if( !strempty( endptr ) )  // syntax error
00132         return MB_TYPE_OUT_OF_RANGE;
00133 
00134     // check for overflow (parsing long int, returning int)
00135     value = pval;
00136     if( pval != (long int)value ) return MB_TYPE_OUT_OF_RANGE;
00137 
00138     return MB_SUCCESS;
00139 }
00140 
00141 ErrorCode FileOptions::get_int_option( const char* name, int default_val, int& value ) const
00142 {
00143     const char* s;
00144     ErrorCode rval = get_option( name, s );
00145     if( MB_SUCCESS != rval ) return rval;
00146 
00147     // empty string
00148     if( strempty( s ) )
00149     {
00150         value = default_val;
00151         return MB_SUCCESS;
00152     }
00153 
00154     // parse value
00155     char* endptr;
00156     long int pval = strtol( s, &endptr, 0 );
00157     if( !strempty( endptr ) )  // syntax error
00158         return MB_TYPE_OUT_OF_RANGE;
00159 
00160     // check for overflow (parsing long int, returning int)
00161     value = pval;
00162     if( pval != (long int)value ) return MB_TYPE_OUT_OF_RANGE;
00163 
00164     return MB_SUCCESS;
00165 }
00166 
00167 ErrorCode FileOptions::get_ints_option( const char* name, std::vector< int >& values ) const
00168 {
00169     const char* s;
00170     ErrorCode rval = get_option( name, s );
00171     if( MB_SUCCESS != rval ) return rval;
00172 
00173     // empty string
00174     if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
00175 
00176     // parse values
00177     while( !strempty( s ) )
00178     {
00179         char* endptr;
00180         long int sval = strtol( s, &endptr, 0 );
00181 
00182 #define EATSPACE( a )                                             \
00183     while( ( *( a ) == ' ' || *( a ) == ',' ) && !strempty( a ) ) \
00184         ( a )++;
00185         EATSPACE( endptr );
00186         long int eval = sval;
00187         if( *endptr == '-' )
00188         {
00189             endptr++;
00190             s    = endptr;
00191             eval = strtol( s, &endptr, 0 );
00192             EATSPACE( endptr );
00193         }
00194 
00195         // check for overflow (parsing long int, returning int)
00196         int value = sval;
00197         if( sval != (long int)value ) return MB_TYPE_OUT_OF_RANGE;
00198         value = eval;
00199         if( eval != (long int)value ) return MB_TYPE_OUT_OF_RANGE;
00200 
00201         for( int i = sval; i <= eval; i++ )
00202             values.push_back( i );
00203 
00204         s = endptr;
00205     }
00206 
00207     return MB_SUCCESS;
00208 }
00209 
00210 ErrorCode FileOptions::get_reals_option( const char* name, std::vector< double >& values ) const
00211 {
00212     const char* s;
00213     ErrorCode rval = get_option( name, s );
00214     if( MB_SUCCESS != rval ) return rval;
00215 
00216     // empty string
00217     if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
00218 
00219     // parse values
00220     while( !strempty( s ) )
00221     {
00222         char* endptr;
00223         double sval = strtod( s, &endptr );
00224 
00225         EATSPACE( endptr );
00226         values.push_back( sval );
00227 
00228         s = endptr;
00229     }
00230 
00231     return MB_SUCCESS;
00232 }
00233 
00234 ErrorCode FileOptions::get_real_option( const char* name, double& value ) const
00235 {
00236     const char* s;
00237     ErrorCode rval = get_option( name, s );
00238     if( MB_SUCCESS != rval ) return rval;
00239 
00240     // empty string
00241     if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
00242 
00243     // parse value
00244     char* endptr;
00245     value = strtod( s, &endptr );
00246     if( !strempty( endptr ) )  // syntax error
00247         return MB_TYPE_OUT_OF_RANGE;
00248 
00249     return MB_SUCCESS;
00250 }
00251 
00252 ErrorCode FileOptions::get_strs_option( const char* name, std::vector< std::string >& values ) const
00253 {
00254     const char* s;
00255     ErrorCode rval = get_option( name, s );
00256     if( MB_SUCCESS != rval ) return rval;
00257 
00258     // empty string
00259     if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
00260 
00261     // parse values
00262     char separator[3] = { ' ', ',', '\0' };
00263     char* tmp_str     = strdup( s );
00264     for( char* i = strtok( tmp_str, separator ); i; i = strtok( 0, separator ) )
00265         if( !strempty( i ) )  // skip empty strings
00266             values.push_back( std::string( i ) );
00267     free( tmp_str );
00268 
00269     return MB_SUCCESS;
00270 }
00271 
00272 ErrorCode FileOptions::get_str_option( const char* name, std::string& value ) const
00273 {
00274     const char* s;
00275     ErrorCode rval = get_option( name, s );
00276     if( MB_SUCCESS != rval ) return rval;
00277     if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
00278     value = s;
00279     return MB_SUCCESS;
00280 }
00281 
00282 ErrorCode FileOptions::get_option( const char* name, std::string& value ) const
00283 {
00284     const char* s;
00285     ErrorCode rval = get_option( name, s );
00286     if( MB_SUCCESS != rval ) return rval;
00287 
00288     value = s;
00289     return MB_SUCCESS;
00290 }
00291 
00292 ErrorCode FileOptions::get_option( const char* name, const char*& value ) const
00293 {
00294     std::vector< const char* >::const_iterator i;
00295     for( i = mOptions.begin(); i != mOptions.end(); ++i )
00296     {
00297         const char* opt = *i;
00298         if( compare( name, opt ) )
00299         {
00300             value = opt + strlen( name );
00301             // if compare returned true, next char after option
00302             // name must be either the null char or an equals symbol.
00303             if( *value == '=' ) ++value;
00304 
00305             mSeen[i - mOptions.begin()] = true;
00306             return MB_SUCCESS;
00307         }
00308     }
00309 
00310     return MB_ENTITY_NOT_FOUND;
00311 }
00312 
00313 ErrorCode FileOptions::match_option( const char* name, const char* value ) const
00314 {
00315     int idx;
00316     const char* array[] = { value, NULL };
00317     return match_option( name, array, idx );
00318 }
00319 
00320 ErrorCode FileOptions::match_option( const char* name, const char* const* values, int& index ) const
00321 {
00322     const char* optval;
00323     ErrorCode rval = get_option( name, optval );
00324     if( MB_SUCCESS != rval ) return rval;
00325 
00326     for( index = 0; values[index]; ++index )
00327         if( compare( optval, values[index] ) ) return MB_SUCCESS;
00328 
00329     index = -1;
00330     return MB_FAILURE;
00331 }
00332 
00333 ErrorCode FileOptions::get_toggle_option( const char* name, bool default_value, bool& value ) const
00334 {
00335     static const char* values[] = { "true", "yes", "1", "on", "false", "no", "0", "off", 0 };
00336     const int num_true          = 4;
00337 
00338     int index;
00339     ErrorCode result = match_option( name, values, index );
00340     if( result == MB_SUCCESS ) { value = index < num_true; }
00341     else if( result == MB_ENTITY_NOT_FOUND )
00342     {
00343         value  = default_value;
00344         result = MB_SUCCESS;
00345     }
00346     else
00347     {
00348         result = MB_TYPE_OUT_OF_RANGE;
00349     }
00350 
00351     return result;
00352 }
00353 
00354 bool FileOptions::compare( const char* name, const char* option )
00355 {
00356     while( !strempty( name ) && toupper( *name ) == toupper( *option ) )
00357     {
00358         ++name;
00359         ++option;
00360     }
00361     // match if name matched option for length of name,
00362     // and option either matched entirely or matches up to
00363     // and equals sign.
00364     return strempty( name ) && ( strempty( option ) || *option == '=' );
00365 }
00366 
00367 void FileOptions::get_options( std::vector< std::string >& list ) const
00368 {
00369     list.clear();
00370     list.resize( mOptions.size() );
00371     std::copy( mOptions.begin(), mOptions.end(), list.begin() );
00372 }
00373 
00374 bool FileOptions::all_seen() const
00375 {
00376     return std::find( mSeen.begin(), mSeen.end(), false ) == mSeen.end();
00377 }
00378 
00379 void FileOptions::mark_all_seen() const
00380 {
00381     mSeen.clear();
00382     mSeen.resize( mOptions.size(), true );
00383 }
00384 
00385 ErrorCode FileOptions::get_unseen_option( std::string& name ) const
00386 {
00387     std::vector< bool >::iterator i = std::find( mSeen.begin(), mSeen.end(), false );
00388     if( i == mSeen.end() )
00389     {
00390         name.clear();
00391         return MB_ENTITY_NOT_FOUND;
00392     }
00393 
00394     const char* opt = mOptions[i - mSeen.begin()];
00395     const char* end = strchr( opt, '=' );
00396     name            = end ? std::string( opt, end - opt ) : std::string( opt );
00397     return MB_SUCCESS;
00398 }
00399 
00400 }  // namespace moab
00401 
00402 #ifdef TEST
00403 
00404 using namespace moab;
00405 
00406 #include <iostream>
00407 
00408 #define CHECK( A )                                                                            \
00409     if( MB_SUCCESS != ( A ) )                                                                 \
00410     {                                                                                         \
00411         std::cerr << "Failure at line " << __LINE__ << ": error code " << ( A ) << std::endl; \
00412         return 1;                                                                             \
00413     }
00414 
00415 #define EQUAL( A, B )                                                                                               \
00416     if( ( A ) != ( B ) )                                                                                            \
00417     {                                                                                                               \
00418         std::cerr << "Failure at line " << __LINE__ << ": expected " << ( B ) << " but got " << ( A ) << std::endl; \
00419         return 2;                                                                                                   \
00420     }
00421 
00422 int main()
00423 {
00424     FileOptions tool( "INT1=1;NUL1;STR1=ABC;DBL1=1.0;dbl2=2.0;DBL3=3.0;INT2=2;nul2;NUL3;INT3=3;str2=once upon a "
00425                       "time;str3==fubar=;;INTS=1-3,5,6;DBLS=1.0,2.0, 3.0;STRS=var1, var2_var2;STRS2=" );
00426 
00427     std::string s;
00428     int i;
00429     double d;
00430     ErrorCode rval;
00431 
00432     // test basic get_option method without deleting entry
00433     rval = tool.get_option( "STR1", s );
00434     CHECK( rval );
00435     EQUAL( s, "ABC" );
00436 
00437     // test basic get_option method again, this time deleting the entry
00438     rval = tool.get_option( "STR1", s );
00439     CHECK( rval );
00440     EQUAL( s, "ABC" );
00441 
00442     // test basig get_option method with a null option
00443     rval = tool.get_option( "NUL2", s );
00444     CHECK( rval );
00445     EQUAL( s.empty(), true );
00446 
00447     // test null option
00448     rval = tool.get_null_option( "nul1" );
00449     CHECK( rval );
00450 
00451     // try null option method on non-null value
00452     rval = tool.get_null_option( "INT1" );
00453     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00454 
00455     // test integer option
00456     rval = tool.get_int_option( "int1", i );
00457     CHECK( rval );
00458     EQUAL( i, 1 );
00459 
00460     rval = tool.get_int_option( "int2", i );
00461     CHECK( rval );
00462     EQUAL( i, 2 );
00463 
00464     // test integer option on non-integer value
00465     rval = tool.get_int_option( "dbl2", i );
00466     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00467 
00468     // test integer option on null value
00469     rval = tool.get_int_option( "NUL3", i );
00470     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00471 
00472     // test double option
00473     rval = tool.get_real_option( "dbl1", d );
00474     CHECK( rval );
00475     EQUAL( d, 1.0 );
00476 
00477     rval = tool.get_real_option( "dbl2", d );
00478     CHECK( rval );
00479     EQUAL( d, 2.0 );
00480 
00481     rval = tool.get_real_option( "int3", d );
00482     CHECK( rval );
00483     EQUAL( d, 3.0 );
00484 
00485     // test real option on non-real value
00486     rval = tool.get_real_option( "str2", d );
00487     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00488 
00489     // test real option on null value
00490     rval = tool.get_real_option( "NUL3", d );
00491     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00492 
00493     // test get a simple string option
00494     rval = tool.get_str_option( "DBL3", s );
00495     CHECK( rval );
00496     EQUAL( s, "3.0" );
00497 
00498     // test get a string with spaces
00499     rval = tool.get_str_option( "STR2", s );
00500     CHECK( rval );
00501     EQUAL( s, "once upon a time" );
00502 
00503     // try to get a string value for a null option
00504     rval = tool.get_str_option( "nul3", s );
00505     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00506 
00507     // We haven't looked at all of the options yet
00508     EQUAL( false, tool.all_seen() );
00509     rval = tool.get_unseen_option( s );
00510     CHECK( rval );
00511     EQUAL( s, "str3" );
00512 
00513     // test options using generic get_option method
00514 
00515     rval = tool.get_option( "NUL3", s );
00516     CHECK( rval );
00517     EQUAL( s.empty(), true );
00518 
00519     rval = tool.get_option( "STR3", s );
00520     CHECK( rval );
00521     EQUAL( s, "=fubar=" );
00522 
00523     // test size of options string
00524     unsigned l = tool.size();
00525     EQUAL( l, 16u );
00526 
00527     // test ints option
00528     std::vector< int > ivals;
00529     rval = tool.get_ints_option( "INTS", ivals );
00530     CHECK( rval );
00531     EQUAL( 5, ivals.size() );
00532     EQUAL( 1, ivals[0] );
00533     EQUAL( 2, ivals[1] );
00534     EQUAL( 3, ivals[2] );
00535     EQUAL( 5, ivals[3] );
00536     EQUAL( 6, ivals[4] );
00537 
00538     // test dbls option
00539     std::vector< double > vals;
00540     rval = tool.get_reals_option( "DBLS", vals );
00541     CHECK( rval );
00542     EQUAL( 3, vals.size() );
00543     EQUAL( 1.0, vals[0] );
00544     EQUAL( 2.0, vals[1] );
00545     EQUAL( 3.0, vals[2] );
00546 
00547     // test strs option
00548     std::vector< std::string > svals;
00549     rval = tool.get_strs_option( "STRS", svals );
00550     CHECK( rval );
00551     EQUAL( 2, svals.size() );
00552     EQUAL( "var1", svals[0] );
00553     EQUAL( "var2_var2", svals[1] );
00554 
00555     svals.clear();
00556     rval = tool.get_strs_option( "STRS2", svals );
00557     EQUAL( MB_TYPE_OUT_OF_RANGE, rval );
00558 
00559     // We requested every option
00560     EQUAL( true, tool.all_seen() );
00561     rval = tool.get_unseen_option( s );
00562     EQUAL( MB_ENTITY_NOT_FOUND, rval );
00563 
00564     // test alternate separator
00565 
00566     FileOptions tool2( ";+OPT1=ABC+OPT2=" );
00567     l = tool2.size();
00568     EQUAL( l, 2 );
00569 
00570     // We haven't looked at all of the options yet
00571     EQUAL( false, tool2.all_seen() );
00572     rval = tool2.get_unseen_option( s );
00573     CHECK( rval );
00574     EQUAL( s, "OPT1" );
00575 
00576     rval = tool2.get_option( "opt1", s );
00577     CHECK( rval );
00578     EQUAL( s, "ABC" );
00579 
00580     rval = tool2.get_option( "opt2", s );
00581     CHECK( rval );
00582     bool e = s.empty();
00583     EQUAL( e, true );
00584 
00585     l = tool2.size();
00586     EQUAL( l, 2 );
00587 
00588     // We requested every option
00589     EQUAL( true, tool2.all_seen() );
00590     rval = tool2.get_unseen_option( s );
00591     EQUAL( MB_ENTITY_NOT_FOUND, rval );
00592 
00593     // test empty options string
00594 
00595     FileOptions tool3( ";;;;" );
00596     e = tool3.empty();
00597     EQUAL( e, true );
00598     l = tool3.size();
00599     EQUAL( l, 0 );
00600     EQUAL( true, tool3.all_seen() );
00601 
00602     FileOptions tool4( NULL );
00603     e = tool4.empty();
00604     EQUAL( e, true );
00605     l = tool4.size();
00606     EQUAL( l, 0 );
00607     EQUAL( true, tool4.all_seen() );
00608 
00609     FileOptions tool5( ";+" );
00610     e = tool5.empty();
00611     EQUAL( e, true );
00612     l = tool5.size();
00613     EQUAL( l, 0 );
00614     EQUAL( true, tool5.all_seen() );
00615 
00616     // test copy constructor
00617 
00618     const FileOptions& tool6( tool2 );
00619 
00620     rval = tool6.get_option( "opt1", s );
00621     CHECK( rval );
00622     EQUAL( s, "ABC" );
00623 
00624     rval = tool6.get_option( "opt2", s );
00625     CHECK( rval );
00626     e = s.empty();
00627     EQUAL( e, true );
00628 
00629     l = tool6.size();
00630     EQUAL( l, 2 );
00631 
00632     const FileOptions& tool7( tool5 );
00633     e = tool7.empty();
00634     EQUAL( e, true );
00635     l = tool7.size();
00636     EQUAL( l, 0 );
00637 
00638     // test assignment operator
00639 
00640     FileOptions tool8( tool2 );
00641     tool8 = tool;
00642     EQUAL( tool8.size(), tool.size() );
00643 
00644     return 0;
00645 }
00646 
00647 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines