Loading [MathJax]/extensions/tex2jax.js
Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FileOptions.cpp
Go to the documentation of this file.
1 /* 2  * MOAB, a Mesh-Oriented datABase, is a software component for creating, 3  * storing and accessing finite element mesh data. 4  * 5  * Copyright 2004 Sandia Corporation. Under the terms of Contract 6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 7  * retains certain rights in this software. 8  * 9  * This library is free software; you can redistribute it and/or 10  * modify it under the terms of the GNU Lesser General Public 11  * License as published by the Free Software Foundation; either 12  * version 2.1 of the License, or (at your option) any later version. 13  * 14  */ 15  16 /**\file FileOptions.cpp 17  *\author Jason Kraftcheck (kraftche@cae.wisc.edu) 18  *\date 2007-08-21 19  */ 20  21 #include "moab/FileOptions.hpp" 22  23 #include <cctype> 24 #include <cstdlib> 25 #include <cstring> 26 #include <algorithm> 27  28 namespace moab 29 { 30  31 const char DEFAULT_SEPARATOR = ';'; 32  33 static inline bool strempty( const char* s ) 34 { 35  return !*s; 36 } 37  38 FileOptions::FileOptions( const char* str ) : mData( 0 ) 39 { 40  // if option string is null, just return 41  if( !str ) return; 42  43  // check if alternate separator is specified 44  char separator[2] = { DEFAULT_SEPARATOR, '\0' }; 45  if( *str == DEFAULT_SEPARATOR ) 46  { 47  ++str; 48  if( strempty( str ) ) return; 49  separator[0] = *str; 50  ++str; 51  } 52  53  // don't bother allocating copy of input string if 54  // input string is empty. 55  if( !strempty( str ) ) 56  { 57  // tokenize at separator character 58  mData = strdup( str ); 59  for( char* i = strtok( mData, separator ); i; i = strtok( 0, separator ) ) 60  if( !strempty( i ) ) // skip empty strings 61  mOptions.push_back( i ); 62  } 63  64  mSeen.resize( mOptions.size(), false ); 65 } 66  67 FileOptions::FileOptions( const FileOptions& copy ) : mData( 0 ), mOptions( copy.mOptions.size() ) 68 { 69  if( !copy.mOptions.empty() ) 70  { 71  const char* last = copy.mOptions.back(); 72  const char* endptr = last + strlen( last ) + 1; 73  size_t len = endptr - copy.mData; 74  mData = (char*)malloc( len ); 75  memcpy( mData, copy.mData, len ); 76  for( size_t i = 0; i < mOptions.size(); ++i ) 77  mOptions[i] = mData + ( copy.mOptions[i] - copy.mData ); 78  } 79  mSeen = copy.mSeen; 80 } 81  82 FileOptions& FileOptions::operator=( const FileOptions& copy ) 83 { 84  // Check for self-assignment 85  if( this == &copy ) return *this; 86  87  free( mData ); 88  mData = 0; 89  mOptions.resize( copy.mOptions.size() ); 90  91  if( !copy.mOptions.empty() ) 92  { 93  const char* last = copy.mOptions.back(); 94  const char* endptr = last + strlen( last ) + 1; 95  size_t len = endptr - copy.mData; 96  mData = (char*)malloc( len ); 97  memcpy( mData, copy.mData, len ); 98  for( size_t i = 0; i < mOptions.size(); ++i ) 99  mOptions[i] = mData + ( copy.mOptions[i] - copy.mData ); 100  } 101  102  mSeen = copy.mSeen; 103  return *this; 104 } 105  106 FileOptions::~FileOptions() 107 { 108  free( mData ); 109 } 110  111 ErrorCode FileOptions::get_null_option( const char* name ) const 112 { 113  const char* s; 114  ErrorCode rval = get_option( name, s ); 115  if( MB_SUCCESS != rval ) return rval; 116  return strempty( s ) ? MB_SUCCESS : MB_TYPE_OUT_OF_RANGE; 117 } 118  119 ErrorCode FileOptions::get_int_option( const char* name, int& value ) const 120 { 121  const char* s; 122  ErrorCode rval = get_option( name, s ); 123  if( MB_SUCCESS != rval ) return rval; 124  125  // empty string 126  if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE; 127  128  // parse value 129  char* endptr; 130  long int pval = strtol( s, &endptr, 0 ); 131  if( !strempty( endptr ) ) // syntax error 132  return MB_TYPE_OUT_OF_RANGE; 133  134  // check for overflow (parsing long int, returning int) 135  value = pval; 136  if( pval != (long int)value ) return MB_TYPE_OUT_OF_RANGE; 137  138  return MB_SUCCESS; 139 } 140  141 ErrorCode FileOptions::get_int_option( const char* name, int default_val, int& value ) const 142 { 143  const char* s; 144  ErrorCode rval = get_option( name, s ); 145  if( MB_SUCCESS != rval ) return rval; 146  147  // empty string 148  if( strempty( s ) ) 149  { 150  value = default_val; 151  return MB_SUCCESS; 152  } 153  154  // parse value 155  char* endptr; 156  long int pval = strtol( s, &endptr, 0 ); 157  if( !strempty( endptr ) ) // syntax error 158  return MB_TYPE_OUT_OF_RANGE; 159  160  // check for overflow (parsing long int, returning int) 161  value = pval; 162  if( pval != (long int)value ) return MB_TYPE_OUT_OF_RANGE; 163  164  return MB_SUCCESS; 165 } 166  167 ErrorCode FileOptions::get_ints_option( const char* name, std::vector< int >& values ) const 168 { 169  const char* s; 170  ErrorCode rval = get_option( name, s ); 171  if( MB_SUCCESS != rval ) return rval; 172  173  // empty string 174  if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE; 175  176  // parse values 177  while( !strempty( s ) ) 178  { 179  char* endptr; 180  long int sval = strtol( s, &endptr, 0 ); 181  182 #define EATSPACE( a ) \ 183  while( ( *( a ) == ' ' || *( a ) == ',' ) && !strempty( a ) ) \ 184  ( a )++; 185  EATSPACE( endptr ); 186  long int eval = sval; 187  if( *endptr == '-' ) 188  { 189  endptr++; 190  s = endptr; 191  eval = strtol( s, &endptr, 0 ); 192  EATSPACE( endptr ); 193  } 194  195  // check for overflow (parsing long int, returning int) 196  int value = sval; 197  if( sval != (long int)value ) return MB_TYPE_OUT_OF_RANGE; 198  value = eval; 199  if( eval != (long int)value ) return MB_TYPE_OUT_OF_RANGE; 200  201  for( int i = sval; i <= eval; i++ ) 202  values.push_back( i ); 203  204  s = endptr; 205  } 206  207  return MB_SUCCESS; 208 } 209  210 ErrorCode FileOptions::get_reals_option( const char* name, std::vector< double >& values ) const 211 { 212  const char* s; 213  ErrorCode rval = get_option( name, s ); 214  if( MB_SUCCESS != rval ) return rval; 215  216  // empty string 217  if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE; 218  219  // parse values 220  while( !strempty( s ) ) 221  { 222  char* endptr; 223  double sval = strtod( s, &endptr ); 224  225  EATSPACE( endptr ); 226  values.push_back( sval ); 227  228  s = endptr; 229  } 230  231  return MB_SUCCESS; 232 } 233  234 ErrorCode FileOptions::get_real_option( const char* name, double& value ) const 235 { 236  const char* s; 237  ErrorCode rval = get_option( name, s ); 238  if( MB_SUCCESS != rval ) return rval; 239  240  // empty string 241  if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE; 242  243  // parse value 244  char* endptr; 245  value = strtod( s, &endptr ); 246  if( !strempty( endptr ) ) // syntax error 247  return MB_TYPE_OUT_OF_RANGE; 248  249  return MB_SUCCESS; 250 } 251  252 ErrorCode FileOptions::get_strs_option( const char* name, std::vector< std::string >& values ) const 253 { 254  const char* s; 255  ErrorCode rval = get_option( name, s ); 256  if( MB_SUCCESS != rval ) return rval; 257  258  // empty string 259  if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE; 260  261  // parse values 262  char separator[3] = { ' ', ',', '\0' }; 263  char* tmp_str = strdup( s ); 264  for( char* i = strtok( tmp_str, separator ); i; i = strtok( 0, separator ) ) 265  if( !strempty( i ) ) // skip empty strings 266  values.push_back( std::string( i ) ); 267  free( tmp_str ); 268  269  return MB_SUCCESS; 270 } 271  272 ErrorCode FileOptions::get_str_option( const char* name, std::string& value ) const 273 { 274  const char* s; 275  ErrorCode rval = get_option( name, s ); 276  if( MB_SUCCESS != rval ) return rval; 277  if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE; 278  value = s; 279  return MB_SUCCESS; 280 } 281  282 ErrorCode FileOptions::get_option( const char* name, std::string& value ) const 283 { 284  const char* s; 285  ErrorCode rval = get_option( name, s ); 286  if( MB_SUCCESS != rval ) return rval; 287  288  value = s; 289  return MB_SUCCESS; 290 } 291  292 ErrorCode FileOptions::get_option( const char* name, const char*& value ) const 293 { 294  std::vector< const char* >::const_iterator i; 295  for( i = mOptions.begin(); i != mOptions.end(); ++i ) 296  { 297  const char* opt = *i; 298  if( compare( name, opt ) ) 299  { 300  value = opt + strlen( name ); 301  // if compare returned true, next char after option 302  // name must be either the null char or an equals symbol. 303  if( *value == '=' ) ++value; 304  305  mSeen[i - mOptions.begin()] = true; 306  return MB_SUCCESS; 307  } 308  } 309  310  return MB_ENTITY_NOT_FOUND; 311 } 312  313 ErrorCode FileOptions::match_option( const char* name, const char* value ) const 314 { 315  int idx; 316  const char* array[] = { value, NULL }; 317  return match_option( name, array, idx ); 318 } 319  320 ErrorCode FileOptions::match_option( const char* name, const char* const* values, int& index ) const 321 { 322  const char* optval; 323  ErrorCode rval = get_option( name, optval ); 324  if( MB_SUCCESS != rval ) return rval; 325  326  for( index = 0; values[index]; ++index ) 327  if( compare( optval, values[index] ) ) return MB_SUCCESS; 328  329  index = -1; 330  return MB_FAILURE; 331 } 332  333 ErrorCode FileOptions::get_toggle_option( const char* name, bool default_value, bool& value ) const 334 { 335  static const char* values[] = { "true", "yes", "1", "on", "false", "no", "0", "off", 0 }; 336  const int num_true = 4; 337  338  int index; 339  ErrorCode result = match_option( name, values, index ); 340  if( result == MB_SUCCESS ) 341  { 342  value = index < num_true; 343  } 344  else if( result == MB_ENTITY_NOT_FOUND ) 345  { 346  value = default_value; 347  result = MB_SUCCESS; 348  } 349  else 350  { 351  result = MB_TYPE_OUT_OF_RANGE; 352  } 353  354  return result; 355 } 356  357 bool FileOptions::compare( const char* name, const char* option ) 358 { 359  while( !strempty( name ) && toupper( *name ) == toupper( *option ) ) 360  { 361  ++name; 362  ++option; 363  } 364  // match if name matched option for length of name, 365  // and option either matched entirely or matches up to 366  // and equals sign. 367  return strempty( name ) && ( strempty( option ) || *option == '=' ); 368 } 369  370 void FileOptions::get_options( std::vector< std::string >& list ) const 371 { 372  list.clear(); 373  list.resize( mOptions.size() ); 374  std::copy( mOptions.begin(), mOptions.end(), list.begin() ); 375 } 376  377 bool FileOptions::all_seen() const 378 { 379  return std::find( mSeen.begin(), mSeen.end(), false ) == mSeen.end(); 380 } 381  382 void FileOptions::mark_all_seen() const 383 { 384  mSeen.clear(); 385  mSeen.resize( mOptions.size(), true ); 386 } 387  388 ErrorCode FileOptions::get_unseen_option( std::string& name ) const 389 { 390  std::vector< bool >::iterator i = std::find( mSeen.begin(), mSeen.end(), false ); 391  if( i == mSeen.end() ) 392  { 393  name.clear(); 394  return MB_ENTITY_NOT_FOUND; 395  } 396  397  const char* opt = mOptions[i - mSeen.begin()]; 398  const char* end = strchr( opt, '=' ); 399  name = end ? std::string( opt, end - opt ) : std::string( opt ); 400  return MB_SUCCESS; 401 } 402  403 } // namespace moab 404  405 #ifdef TEST 406  407 using namespace moab; 408  409 #include <iostream> 410  411 #define CHECK( A ) \ 412  if( MB_SUCCESS != ( A ) ) \ 413  { \ 414  std::cerr << "Failure at line " << __LINE__ << ": error code " << ( A ) << std::endl; \ 415  return 1; \ 416  } 417  418 #define EQUAL( A, B ) \ 419  if( ( A ) != ( B ) ) \ 420  { \ 421  std::cerr << "Failure at line " << __LINE__ << ": expected " << ( B ) << " but got " << ( A ) << std::endl; \ 422  return 2; \ 423  } 424  425 int main() 426 { 427  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 " 428  "time;str3==fubar=;;INTS=1-3,5,6;DBLS=1.0,2.0, 3.0;STRS=var1, var2_var2;STRS2=" ); 429  430  std::string s; 431  int i; 432  double d; 433  ErrorCode rval; 434  435  // test basic get_option method without deleting entry 436  rval = tool.get_option( "STR1", s ); 437  CHECK( rval ); 438  EQUAL( s, "ABC" ); 439  440  // test basic get_option method again, this time deleting the entry 441  rval = tool.get_option( "STR1", s ); 442  CHECK( rval ); 443  EQUAL( s, "ABC" ); 444  445  // test basig get_option method with a null option 446  rval = tool.get_option( "NUL2", s ); 447  CHECK( rval ); 448  EQUAL( s.empty(), true ); 449  450  // test null option 451  rval = tool.get_null_option( "nul1" ); 452  CHECK( rval ); 453  454  // try null option method on non-null value 455  rval = tool.get_null_option( "INT1" ); 456  EQUAL( rval, MB_TYPE_OUT_OF_RANGE ); 457  458  // test integer option 459  rval = tool.get_int_option( "int1", i ); 460  CHECK( rval ); 461  EQUAL( i, 1 ); 462  463  rval = tool.get_int_option( "int2", i ); 464  CHECK( rval ); 465  EQUAL( i, 2 ); 466  467  // test integer option on non-integer value 468  rval = tool.get_int_option( "dbl2", i ); 469  EQUAL( rval, MB_TYPE_OUT_OF_RANGE ); 470  471  // test integer option on null value 472  rval = tool.get_int_option( "NUL3", i ); 473  EQUAL( rval, MB_TYPE_OUT_OF_RANGE ); 474  475  // test double option 476  rval = tool.get_real_option( "dbl1", d ); 477  CHECK( rval ); 478  EQUAL( d, 1.0 ); 479  480  rval = tool.get_real_option( "dbl2", d ); 481  CHECK( rval ); 482  EQUAL( d, 2.0 ); 483  484  rval = tool.get_real_option( "int3", d ); 485  CHECK( rval ); 486  EQUAL( d, 3.0 ); 487  488  // test real option on non-real value 489  rval = tool.get_real_option( "str2", d ); 490  EQUAL( rval, MB_TYPE_OUT_OF_RANGE ); 491  492  // test real option on null value 493  rval = tool.get_real_option( "NUL3", d ); 494  EQUAL( rval, MB_TYPE_OUT_OF_RANGE ); 495  496  // test get a simple string option 497  rval = tool.get_str_option( "DBL3", s ); 498  CHECK( rval ); 499  EQUAL( s, "3.0" ); 500  501  // test get a string with spaces 502  rval = tool.get_str_option( "STR2", s ); 503  CHECK( rval ); 504  EQUAL( s, "once upon a time" ); 505  506  // try to get a string value for a null option 507  rval = tool.get_str_option( "nul3", s ); 508  EQUAL( rval, MB_TYPE_OUT_OF_RANGE ); 509  510  // We haven't looked at all of the options yet 511  EQUAL( false, tool.all_seen() ); 512  rval = tool.get_unseen_option( s ); 513  CHECK( rval ); 514  EQUAL( s, "str3" ); 515  516  // test options using generic get_option method 517  518  rval = tool.get_option( "NUL3", s ); 519  CHECK( rval ); 520  EQUAL( s.empty(), true ); 521  522  rval = tool.get_option( "STR3", s ); 523  CHECK( rval ); 524  EQUAL( s, "=fubar=" ); 525  526  // test size of options string 527  unsigned l = tool.size(); 528  EQUAL( l, 16u ); 529  530  // test ints option 531  std::vector< int > ivals; 532  rval = tool.get_ints_option( "INTS", ivals ); 533  CHECK( rval ); 534  EQUAL( 5, ivals.size() ); 535  EQUAL( 1, ivals[0] ); 536  EQUAL( 2, ivals[1] ); 537  EQUAL( 3, ivals[2] ); 538  EQUAL( 5, ivals[3] ); 539  EQUAL( 6, ivals[4] ); 540  541  // test dbls option 542  std::vector< double > vals; 543  rval = tool.get_reals_option( "DBLS", vals ); 544  CHECK( rval ); 545  EQUAL( 3, vals.size() ); 546  EQUAL( 1.0, vals[0] ); 547  EQUAL( 2.0, vals[1] ); 548  EQUAL( 3.0, vals[2] ); 549  550  // test strs option 551  std::vector< std::string > svals; 552  rval = tool.get_strs_option( "STRS", svals ); 553  CHECK( rval ); 554  EQUAL( 2, svals.size() ); 555  EQUAL( "var1", svals[0] ); 556  EQUAL( "var2_var2", svals[1] ); 557  558  svals.clear(); 559  rval = tool.get_strs_option( "STRS2", svals ); 560  EQUAL( MB_TYPE_OUT_OF_RANGE, rval ); 561  562  // We requested every option 563  EQUAL( true, tool.all_seen() ); 564  rval = tool.get_unseen_option( s ); 565  EQUAL( MB_ENTITY_NOT_FOUND, rval ); 566  567  // test alternate separator 568  569  FileOptions tool2( ";+OPT1=ABC+OPT2=" ); 570  l = tool2.size(); 571  EQUAL( l, 2 ); 572  573  // We haven't looked at all of the options yet 574  EQUAL( false, tool2.all_seen() ); 575  rval = tool2.get_unseen_option( s ); 576  CHECK( rval ); 577  EQUAL( s, "OPT1" ); 578  579  rval = tool2.get_option( "opt1", s ); 580  CHECK( rval ); 581  EQUAL( s, "ABC" ); 582  583  rval = tool2.get_option( "opt2", s ); 584  CHECK( rval ); 585  bool e = s.empty(); 586  EQUAL( e, true ); 587  588  l = tool2.size(); 589  EQUAL( l, 2 ); 590  591  // We requested every option 592  EQUAL( true, tool2.all_seen() ); 593  rval = tool2.get_unseen_option( s ); 594  EQUAL( MB_ENTITY_NOT_FOUND, rval ); 595  596  // test empty options string 597  598  FileOptions tool3( ";;;;" ); 599  e = tool3.empty(); 600  EQUAL( e, true ); 601  l = tool3.size(); 602  EQUAL( l, 0 ); 603  EQUAL( true, tool3.all_seen() ); 604  605  FileOptions tool4( NULL ); 606  e = tool4.empty(); 607  EQUAL( e, true ); 608  l = tool4.size(); 609  EQUAL( l, 0 ); 610  EQUAL( true, tool4.all_seen() ); 611  612  FileOptions tool5( ";+" ); 613  e = tool5.empty(); 614  EQUAL( e, true ); 615  l = tool5.size(); 616  EQUAL( l, 0 ); 617  EQUAL( true, tool5.all_seen() ); 618  619  // test copy constructor 620  621  const FileOptions& tool6( tool2 ); 622  623  rval = tool6.get_option( "opt1", s ); 624  CHECK( rval ); 625  EQUAL( s, "ABC" ); 626  627  rval = tool6.get_option( "opt2", s ); 628  CHECK( rval ); 629  e = s.empty(); 630  EQUAL( e, true ); 631  632  l = tool6.size(); 633  EQUAL( l, 2 ); 634  635  const FileOptions& tool7( tool5 ); 636  e = tool7.empty(); 637  EQUAL( e, true ); 638  l = tool7.size(); 639  EQUAL( l, 0 ); 640  641  // test assignment operator 642  643  FileOptions tool8( tool2 ); 644  tool8 = tool; 645  EQUAL( tool8.size(), tool.size() ); 646  647  return 0; 648 } 649  650 #endif