1
15
16
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
41 if( !str ) return;
42
43
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
54
55 if( !strempty( str ) )
56 {
57
58 mData = strdup( str );
59 for( char* i = strtok( mData, separator ); i; i = strtok( 0, separator ) )
60 if( !strempty( i ) )
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
85 if( this == © ) 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
126 if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
127
128
129 char* endptr;
130 long int pval = strtol( s, &endptr, 0 );
131 if( !strempty( endptr ) )
132 return MB_TYPE_OUT_OF_RANGE;
133
134
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
148 if( strempty( s ) )
149 {
150 value = default_val;
151 return MB_SUCCESS;
152 }
153
154
155 char* endptr;
156 long int pval = strtol( s, &endptr, 0 );
157 if( !strempty( endptr ) )
158 return MB_TYPE_OUT_OF_RANGE;
159
160
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
174 if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
175
176
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
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
217 if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
218
219
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
241 if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
242
243
244 char* endptr;
245 value = strtod( s, &endptr );
246 if( !strempty( endptr ) )
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
259 if( strempty( s ) ) return MB_TYPE_OUT_OF_RANGE;
260
261
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 ) )
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
302
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
365
366
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 }
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
436 rval = tool.get_option( "STR1", s );
437 CHECK( rval );
438 EQUAL( s, "ABC" );
439
440
441 rval = tool.get_option( "STR1", s );
442 CHECK( rval );
443 EQUAL( s, "ABC" );
444
445
446 rval = tool.get_option( "NUL2", s );
447 CHECK( rval );
448 EQUAL( s.empty(), true );
449
450
451 rval = tool.get_null_option( "nul1" );
452 CHECK( rval );
453
454
455 rval = tool.get_null_option( "INT1" );
456 EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
457
458
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
468 rval = tool.get_int_option( "dbl2", i );
469 EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
470
471
472 rval = tool.get_int_option( "NUL3", i );
473 EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
474
475
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
489 rval = tool.get_real_option( "str2", d );
490 EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
491
492
493 rval = tool.get_real_option( "NUL3", d );
494 EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
495
496
497 rval = tool.get_str_option( "DBL3", s );
498 CHECK( rval );
499 EQUAL( s, "3.0" );
500
501
502 rval = tool.get_str_option( "STR2", s );
503 CHECK( rval );
504 EQUAL( s, "once upon a time" );
505
506
507 rval = tool.get_str_option( "nul3", s );
508 EQUAL( rval, MB_TYPE_OUT_OF_RANGE );
509
510
511 EQUAL( false, tool.all_seen() );
512 rval = tool.get_unseen_option( s );
513 CHECK( rval );
514 EQUAL( s, "str3" );
515
516
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
527 unsigned l = tool.size();
528 EQUAL( l, 16u );
529
530
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
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
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
563 EQUAL( true, tool.all_seen() );
564 rval = tool.get_unseen_option( s );
565 EQUAL( MB_ENTITY_NOT_FOUND, rval );
566
567
568
569 FileOptions tool2( ";+OPT1=ABC+OPT2=" );
570 l = tool2.size();
571 EQUAL( l, 2 );
572
573
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
592 EQUAL( true, tool2.all_seen() );
593 rval = tool2.get_unseen_option( s );
594 EQUAL( MB_ENTITY_NOT_FOUND, rval );
595
596
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
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
642
643 FileOptions tool8( tool2 );
644 tool8 = tool;
645 EQUAL( tool8.size(), tool.size() );
646
647 return 0;
648 }
649
650 #endif