![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
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
00024 #include
00025 #include
00026 #include
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 == © ) 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
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