Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
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 ([email protected])
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 
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 
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 
378 {
379  return std::find( mSeen.begin(), mSeen.end(), false ) == mSeen.end();
380 }
381 
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