Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
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 ([email protected])
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 )
00341     {
00342         value = index < num_true;
00343     }
00344     else if( result == MB_ENTITY_NOT_FOUND )
00345     {
00346         value  = default_value;
00347         result = MB_SUCCESS;
00348     }
00349     else
00350     {
00351         result = MB_TYPE_OUT_OF_RANGE;
00352     }
00353 
00354     return result;
00355 }
00356 
00357 bool FileOptions::compare( const char* name, const char* option )
00358 {
00359     while( !strempty( name ) && toupper( *name ) == toupper( *option ) )
00360     {
00361         ++name;
00362         ++option;
00363     }
00364     // match if name matched option for length of name,
00365     // and option either matched entirely or matches up to
00366     // and equals sign.
00367     return strempty( name ) && ( strempty( option ) || *option == '=' );
00368 }
00369 
00370 void FileOptions::get_options( std::vector< std::string >& list ) const
00371 {
00372     list.clear();
00373     list.resize( mOptions.size() );
00374     std::copy( mOptions.begin(), mOptions.end(), list.begin() );
00375 }
00376 
00377 bool FileOptions::all_seen() const
00378 {
00379     return std::find( mSeen.begin(), mSeen.end(), false ) == mSeen.end();
00380 }
00381 
00382 void FileOptions::mark_all_seen() const
00383 {
00384     mSeen.clear();
00385     mSeen.resize( mOptions.size(), true );
00386 }
00387 
00388 ErrorCode FileOptions::get_unseen_option( std::string& name ) const
00389 {
00390     std::vector< bool >::iterator i = std::find( mSeen.begin(), mSeen.end(), false );
00391     if( i == mSeen.end() )
00392     {
00393         name.clear();
00394         return MB_ENTITY_NOT_FOUND;
00395     }
00396 
00397     const char* opt = mOptions[i - mSeen.begin()];
00398     const char* end = strchr( opt, '=' );
00399     name            = end ? std::string( opt, end - opt ) : std::string( opt );
00400     return MB_SUCCESS;
00401 }
00402 
00403 }  // namespace moab
00404 
00405 #ifdef TEST
00406 
00407 using namespace moab;
00408 
00409 #include <iostream>
00410 
00411 #define CHECK( A )                                                                            \
00412     if( MB_SUCCESS != ( A ) )                                                                 \
00413     {                                                                                         \
00414         std::cerr << "Failure at line " << __LINE__ << ": error code " << ( A ) << std::endl; \
00415         return 1;                                                                             \
00416     }
00417 
00418 #define EQUAL( A, B )                                                                                               \
00419     if( ( A ) != ( B ) )                                                                                            \
00420     {                                                                                                               \
00421         std::cerr << "Failure at line " << __LINE__ << ": expected " << ( B ) << " but got " << ( A ) << std::endl; \
00422         return 2;                                                                                                   \
00423     }
00424 
00425 int main()
00426 {
00427     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 "
00428                       "time;str3==fubar=;;INTS=1-3,5,6;DBLS=1.0,2.0, 3.0;STRS=var1, var2_var2;STRS2=" );
00429 
00430     std::string s;
00431     int i;
00432     double d;
00433     ErrorCode rval;
00434 
00435     // test basic get_option method without deleting entry
00436     rval = tool.get_option( "STR1", s );
00437     CHECK( rval );
00438     EQUAL( s, "ABC" );
00439 
00440     // test basic get_option method again, this time deleting the entry
00441     rval = tool.get_option( "STR1", s );
00442     CHECK( rval );
00443     EQUAL( s, "ABC" );
00444 
00445     // test basig get_option method with a null option
00446     rval = tool.get_option( "NUL2", s );
00447     CHECK( rval );
00448     EQUAL( s.empty(), true );
00449 
00450     // test null option
00451     rval = tool.get_null_option( "nul1" );
00452     CHECK( rval );
00453 
00454     // try null option method on non-null value
00455     rval = tool.get_null_option( "INT1" );
00456     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00457 
00458     // test integer option
00459     rval = tool.get_int_option( "int1", i );
00460     CHECK( rval );
00461     EQUAL( i, 1 );
00462 
00463     rval = tool.get_int_option( "int2", i );
00464     CHECK( rval );
00465     EQUAL( i, 2 );
00466 
00467     // test integer option on non-integer value
00468     rval = tool.get_int_option( "dbl2", i );
00469     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00470 
00471     // test integer option on null value
00472     rval = tool.get_int_option( "NUL3", i );
00473     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00474 
00475     // test double option
00476     rval = tool.get_real_option( "dbl1", d );
00477     CHECK( rval );
00478     EQUAL( d, 1.0 );
00479 
00480     rval = tool.get_real_option( "dbl2", d );
00481     CHECK( rval );
00482     EQUAL( d, 2.0 );
00483 
00484     rval = tool.get_real_option( "int3", d );
00485     CHECK( rval );
00486     EQUAL( d, 3.0 );
00487 
00488     // test real option on non-real value
00489     rval = tool.get_real_option( "str2", d );
00490     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00491 
00492     // test real option on null value
00493     rval = tool.get_real_option( "NUL3", d );
00494     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00495 
00496     // test get a simple string option
00497     rval = tool.get_str_option( "DBL3", s );
00498     CHECK( rval );
00499     EQUAL( s, "3.0" );
00500 
00501     // test get a string with spaces
00502     rval = tool.get_str_option( "STR2", s );
00503     CHECK( rval );
00504     EQUAL( s, "once upon a time" );
00505 
00506     // try to get a string value for a null option
00507     rval = tool.get_str_option( "nul3", s );
00508     EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
00509 
00510     // We haven't looked at all of the options yet
00511     EQUAL( false, tool.all_seen() );
00512     rval = tool.get_unseen_option( s );
00513     CHECK( rval );
00514     EQUAL( s, "str3" );
00515 
00516     // test options using generic get_option method
00517 
00518     rval = tool.get_option( "NUL3", s );
00519     CHECK( rval );
00520     EQUAL( s.empty(), true );
00521 
00522     rval = tool.get_option( "STR3", s );
00523     CHECK( rval );
00524     EQUAL( s, "=fubar=" );
00525 
00526     // test size of options string
00527     unsigned l = tool.size();
00528     EQUAL( l, 16u );
00529 
00530     // test ints option
00531     std::vector< int > ivals;
00532     rval = tool.get_ints_option( "INTS", ivals );
00533     CHECK( rval );
00534     EQUAL( 5, ivals.size() );
00535     EQUAL( 1, ivals[0] );
00536     EQUAL( 2, ivals[1] );
00537     EQUAL( 3, ivals[2] );
00538     EQUAL( 5, ivals[3] );
00539     EQUAL( 6, ivals[4] );
00540 
00541     // test dbls option
00542     std::vector< double > vals;
00543     rval = tool.get_reals_option( "DBLS", vals );
00544     CHECK( rval );
00545     EQUAL( 3, vals.size() );
00546     EQUAL( 1.0, vals[0] );
00547     EQUAL( 2.0, vals[1] );
00548     EQUAL( 3.0, vals[2] );
00549 
00550     // test strs option
00551     std::vector< std::string > svals;
00552     rval = tool.get_strs_option( "STRS", svals );
00553     CHECK( rval );
00554     EQUAL( 2, svals.size() );
00555     EQUAL( "var1", svals[0] );
00556     EQUAL( "var2_var2", svals[1] );
00557 
00558     svals.clear();
00559     rval = tool.get_strs_option( "STRS2", svals );
00560     EQUAL( MB_TYPE_OUT_OF_RANGE, rval );
00561 
00562     // We requested every option
00563     EQUAL( true, tool.all_seen() );
00564     rval = tool.get_unseen_option( s );
00565     EQUAL( MB_ENTITY_NOT_FOUND, rval );
00566 
00567     // test alternate separator
00568 
00569     FileOptions tool2( ";+OPT1=ABC+OPT2=" );
00570     l = tool2.size();
00571     EQUAL( l, 2 );
00572 
00573     // We haven't looked at all of the options yet
00574     EQUAL( false, tool2.all_seen() );
00575     rval = tool2.get_unseen_option( s );
00576     CHECK( rval );
00577     EQUAL( s, "OPT1" );
00578 
00579     rval = tool2.get_option( "opt1", s );
00580     CHECK( rval );
00581     EQUAL( s, "ABC" );
00582 
00583     rval = tool2.get_option( "opt2", s );
00584     CHECK( rval );
00585     bool e = s.empty();
00586     EQUAL( e, true );
00587 
00588     l = tool2.size();
00589     EQUAL( l, 2 );
00590 
00591     // We requested every option
00592     EQUAL( true, tool2.all_seen() );
00593     rval = tool2.get_unseen_option( s );
00594     EQUAL( MB_ENTITY_NOT_FOUND, rval );
00595 
00596     // test empty options string
00597 
00598     FileOptions tool3( ";;;;" );
00599     e = tool3.empty();
00600     EQUAL( e, true );
00601     l = tool3.size();
00602     EQUAL( l, 0 );
00603     EQUAL( true, tool3.all_seen() );
00604 
00605     FileOptions tool4( NULL );
00606     e = tool4.empty();
00607     EQUAL( e, true );
00608     l = tool4.size();
00609     EQUAL( l, 0 );
00610     EQUAL( true, tool4.all_seen() );
00611 
00612     FileOptions tool5( ";+" );
00613     e = tool5.empty();
00614     EQUAL( e, true );
00615     l = tool5.size();
00616     EQUAL( l, 0 );
00617     EQUAL( true, tool5.all_seen() );
00618 
00619     // test copy constructor
00620 
00621     const FileOptions& tool6( tool2 );
00622 
00623     rval = tool6.get_option( "opt1", s );
00624     CHECK( rval );
00625     EQUAL( s, "ABC" );
00626 
00627     rval = tool6.get_option( "opt2", s );
00628     CHECK( rval );
00629     e = s.empty();
00630     EQUAL( e, true );
00631 
00632     l = tool6.size();
00633     EQUAL( l, 2 );
00634 
00635     const FileOptions& tool7( tool5 );
00636     e = tool7.empty();
00637     EQUAL( e, true );
00638     l = tool7.size();
00639     EQUAL( l, 0 );
00640 
00641     // test assignment operator
00642 
00643     FileOptions tool8( tool2 );
00644     tool8 = tool;
00645     EQUAL( tool8.size(), tool.size() );
00646 
00647     return 0;
00648 }
00649 
00650 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines