Pol  Revision:f37d500
cfgfile.cpp
Go to the documentation of this file.
1 
10 #include "cfgfile.h"
11 
12 #include <ctype.h>
13 #include <exception>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 
18 #include <format/format.h>
19 #include "cfgelem.h"
20 #include "clib.h"
21 #include "logfacility.h"
22 #include "stlutil.h"
23 #include "strutil.h"
24 
25 
26 namespace Pol
27 {
28 namespace Clib
29 {
30 namespace
31 {
32 bool commentline( const std::string& str )
33 {
34 #ifdef __GNUC__
35  return ( ( str[0] == '#' ) || ( str.substr( 0, 2 ) == "//" ) );
36 #else
37  return ( ( str[0] == '#' ) || ( str.compare( 0, 2, "//" ) == 0 ) );
38 #endif
39 }
40 } // namespace
41 
42 ConfigProperty::ConfigProperty( const char* name, const char* value )
43  : name_( name ), value_( value )
44 {
45 }
46 
47 ConfigProperty::ConfigProperty( const std::string& name, const std::string& value )
48  : name_( name ), value_( value )
49 {
50 }
51 
52 ConfigProperty::ConfigProperty( std::string* pname, std::string* pvalue )
53 {
54  pname->swap( name_ );
55  pvalue->swap( value_ );
56 }
57 
59 
60 ConfigElemBase::ConfigElemBase() : type_( "" ), rest_( "" ), _source( NULL ) {}
62 {
63  return type_.capacity() + rest_.capacity() + sizeof( _source );
64 }
65 
67 
69 
71 {
72  size_t size = ConfigElemBase::estimateSize();
73  for ( const auto& ele : properties )
74  size += ele.first.capacity() + ele.second.capacity() + ( sizeof( void* ) * 3 + 1 ) / 2;
75  return size;
76 }
77 
78 
79 const char* ConfigElemBase::type() const
80 {
81  return type_.c_str();
82 }
83 
84 const char* ConfigElemBase::rest() const
85 {
86  return rest_.c_str();
87 }
88 
89 void ConfigElem::set_rest( const char* rest )
90 {
91  rest_ = rest;
92 }
93 
94 void ConfigElem::set_type( const char* type )
95 {
96  type_ = type;
97 }
98 
100 {
101  _source = elem._source;
102 }
104 {
105  _source = source;
106 }
107 
108 bool ConfigElemBase::type_is( const char* type ) const
109 {
110  return ( stricmp( type_.c_str(), type ) == 0 );
111 }
112 
113 bool ConfigElem::remove_first_prop( std::string* propname, std::string* value )
114 {
115  if ( properties.empty() )
116  return false;
117 
118  auto itr = properties.begin();
119  *propname = ( *itr ).first;
120  *value = ( *itr ).second;
121  properties.erase( itr );
122  return true;
123 }
124 
125 bool ConfigElem::has_prop( const char* propname ) const
126 {
127  return properties.count( propname ) != 0;
128 }
129 bool VectorConfigElem::has_prop( const char* propname ) const
130 {
131  for ( const auto& prop : properties )
132  {
133  if ( stricmp( prop->name_.c_str(), propname ) == 0 )
134  {
135  return true;
136  }
137  }
138  return false;
139 }
140 
141 bool ConfigElem::remove_prop( const char* propname, std::string* value )
142 {
143  auto itr = properties.find( propname );
144  if ( itr != properties.end() )
145  {
146  *value = ( *itr ).second;
147  properties.erase( itr );
148  return true;
149  }
150  else
151  {
152  return false;
153  }
154 }
155 bool VectorConfigElem::remove_prop( const char* propname, std::string* value )
156 {
157  auto itr = properties.begin(), end = properties.end();
158  for ( ; itr != end; ++itr )
159  {
160  ConfigProperty* prop = *itr;
161  if ( stricmp( prop->name_.c_str(), propname ) == 0 )
162  {
163  *value = prop->value_;
164  delete prop;
165  properties.erase( itr );
166  return true;
167  }
168  }
169  return false;
170 }
171 
172 bool ConfigElem::read_prop( const char* propname, std::string* value ) const
173 {
174  auto itr = properties.find( propname );
175  if ( itr != properties.end() )
176  {
177  *value = ( *itr ).second;
178  return true;
179  }
180  else
181  {
182  return false;
183  }
184 }
185 bool VectorConfigElem::read_prop( const char* propname, std::string* value ) const
186 {
187  for ( const auto& prop : properties )
188  {
189  if ( stricmp( prop->name_.c_str(), propname ) == 0 )
190  {
191  *value = prop->value_;
192  return true;
193  }
194  }
195  return false;
196 }
197 
198 void ConfigElem::get_prop( const char* propname, unsigned int* plong ) const
199 {
200  auto itr = properties.find( propname );
201  if ( itr != properties.end() )
202  {
203  *plong = strtoul( ( *itr ).second.c_str(), NULL, 0 );
204  }
205  else
206  {
207  throw_error( "SERIAL property not found" );
208  }
209 }
210 
211 bool ConfigElem::remove_prop( const char* propname, unsigned int* plong )
212 {
213  auto itr = properties.find( propname );
214  if ( itr != properties.end() )
215  {
216  *plong = strtoul( ( *itr ).second.c_str(), NULL, 0 );
217  properties.erase( itr );
218  return true;
219  }
220  else
221  {
222  return false;
223  }
224 }
225 bool VectorConfigElem::remove_prop( const char* propname, unsigned int* plong )
226 {
227  auto itr = properties.begin(), end = properties.end();
228  for ( ; itr != end; ++itr )
229  {
230  ConfigProperty* prop = *itr;
231  if ( stricmp( prop->name_.c_str(), propname ) == 0 )
232  {
233  *plong = strtoul( prop->value_.c_str(), NULL, 0 );
234  delete prop;
235  properties.erase( itr );
236  return true;
237  }
238  }
239  return false;
240 }
241 
242 bool ConfigElem::remove_prop( const char* propname, unsigned short* psval )
243 {
244  std::string temp;
245  if ( remove_prop( propname, &temp ) )
246  {
247  // FIXME isdigit isxdigit - +
248  // or, use endptr
249 
250  char* endptr = NULL;
251  *psval = (unsigned short)strtoul( temp.c_str(), &endptr, 0 );
252  if ( ( endptr != NULL ) && ( *endptr != '\0' ) && !isspace( *endptr ) )
253  {
254  std::string errmsg;
255  errmsg = "Poorly formed number in property '";
256  errmsg += propname;
257  errmsg += "': " + temp;
258  throw_error( errmsg );
259  }
260  // FIXME check range within unsigned short
261  return true;
262  }
263  return false;
264 }
265 
267 
268 bool VectorConfigElem::remove_prop( const char* propname, unsigned short* psval )
269 {
270  auto itr = properties.begin(), end = properties.end();
271  for ( ; itr != end; ++itr )
272  {
273  ConfigProperty* prop = *itr;
274  if ( stricmp( prop->name_.c_str(), propname ) == 0 )
275  {
276  // FIXME isdigit isxdigit - +
277  // or, use endptr
278 
279  char* endptr = NULL;
280  *psval = (unsigned short)strtoul( prop->value_.c_str(), &endptr, 0 );
281  if ( ( endptr != NULL ) && ( *endptr != '\0' ) && !isspace( *endptr ) )
282  {
283  std::string errmsg;
284  errmsg = "Poorly formed number in property '";
285  errmsg += propname;
286  errmsg += "': " + prop->value_;
287  throw_error( errmsg );
288  }
289  // FIXME check range within unsigned short
290  delete prop;
291  properties.erase( itr );
292  return true;
293  }
294  }
295  return false;
296 }
297 
298 void ConfigElem::throw_error( const std::string& errmsg ) const
299 {
300  if ( _source != NULL )
301  _source->display_error( errmsg, false, this );
302  throw std::runtime_error( "Configuration file error" );
303 }
304 void VectorConfigElem::throw_error( const std::string& errmsg ) const
305 {
306  if ( _source != NULL )
307  _source->display_error( errmsg, false, this );
308  throw std::runtime_error( "Configuration file error" );
309 }
310 
311 void ConfigElem::warn( const std::string& errmsg ) const
312 {
313  if ( _source != NULL )
314  _source->display_error( errmsg, false, this, false );
315 }
316 
317 void ConfigElem::warn_with_line( const std::string& errmsg ) const
318 {
319  if ( _source != NULL )
320  _source->display_error( errmsg, true, this, false );
321 }
322 
323 void ConfigElem::prop_not_found( const char* propname ) const
324 {
325  std::string errmsg( "Property '" );
326  errmsg += propname;
327  errmsg += "' was not found.";
328  throw_error( errmsg );
329 }
330 
331 unsigned short ConfigElem::remove_ushort( const char* propname )
332 {
333  unsigned short temp;
334  if ( remove_prop( propname, &temp ) )
335  {
336  return temp;
337  }
338  else
339  {
340  prop_not_found( propname ); // prop_not_found throws
341  }
342 }
343 
344 unsigned short ConfigElem::remove_ushort( const char* propname, unsigned short dflt )
345 {
346  unsigned short temp;
347  if ( remove_prop( propname, &temp ) )
348  return temp;
349  else
350  return dflt;
351 }
352 
353 int ConfigElem::remove_int( const char* propname )
354 {
355  std::string temp = remove_string( propname );
356 
357  return atoi( temp.c_str() );
358 }
359 
360 int ConfigElem::remove_int( const char* propname, int dflt )
361 {
362  std::string temp;
363  if ( remove_prop( propname, &temp ) )
364  {
365  return atoi( temp.c_str() );
366  }
367  else
368  {
369  return dflt;
370  }
371 }
372 
373 unsigned ConfigElem::remove_unsigned( const char* propname )
374 {
375  std::string temp = remove_string( propname );
376 
377  return strtoul( temp.c_str(), NULL, 0 ); // TODO check unsigned range
378 }
379 
380 unsigned ConfigElem::remove_unsigned( const char* propname, int dflt )
381 {
382  std::string temp;
383  if ( remove_prop( propname, &temp ) )
384  {
385  return strtoul( temp.c_str(), NULL, 0 ); // TODO check unsigned range
386  }
387  else
388  {
389  return dflt;
390  }
391 }
392 
393 
394 std::string ConfigElem::remove_string( const char* propname )
395 {
396  std::string temp;
397  if ( remove_prop( propname, &temp ) )
398  {
399  return temp;
400  }
401  else
402  {
403  prop_not_found( propname );
404  return ""; // this is not reached, prop_not_found throws
405  }
406 }
407 
408 std::string ConfigElem::read_string( const char* propname ) const
409 {
410  std::string temp;
411  if ( read_prop( propname, &temp ) )
412  {
413  return temp;
414  }
415  else
416  {
417  prop_not_found( propname );
418  return ""; // this is not reached, prop_not_found throws
419  }
420 }
421 std::string ConfigElem::read_string( const char* propname, const char* dflt ) const
422 {
423  std::string temp;
424  if ( read_prop( propname, &temp ) )
425  return temp;
426  else
427  return dflt;
428 }
429 
430 std::string ConfigElem::remove_string( const char* propname, const char* dflt )
431 {
432  std::string temp;
433  if ( remove_prop( propname, &temp ) )
434  return temp;
435  else
436  return dflt;
437 }
438 
439 bool ConfigElem::remove_bool( const char* propname )
440 {
441  return remove_ushort( propname ) ? true : false;
442 }
443 
444 bool ConfigElem::remove_bool( const char* propname, bool dflt )
445 {
446  return remove_ushort( propname, dflt ) ? true : false;
447 }
448 
449 float ConfigElem::remove_float( const char* propname, float dflt )
450 {
451  std::string tmp;
452  if ( remove_prop( propname, &tmp ) )
453  {
454  return static_cast<float>( strtod( tmp.c_str(), NULL ) );
455  }
456  else
457  {
458  return dflt;
459  }
460 }
461 double ConfigElem::remove_double( const char* propname, double dflt )
462 {
463  std::string tmp;
464  if ( remove_prop( propname, &tmp ) )
465  {
466  return strtod( tmp.c_str(), NULL );
467  }
468  else
469  {
470  return dflt;
471  }
472 }
473 
474 unsigned int ConfigElem::remove_ulong( const char* propname )
475 {
476  unsigned int temp;
477  if ( remove_prop( propname, &temp ) )
478  {
479  return temp;
480  }
481  else
482  {
483  prop_not_found( propname ); // prop_not_found throws
484  }
485 }
486 
487 unsigned int ConfigElem::remove_ulong( const char* propname, unsigned int dflt )
488 {
489  unsigned int temp;
490  if ( remove_prop( propname, &temp ) )
491  return temp;
492  else
493  return dflt;
494 }
495 
496 void ConfigElem::clear_prop( const char* propname )
497 {
498  unsigned int dummy;
499  while ( remove_prop( propname, &dummy ) )
500  continue;
501 }
502 
503 void ConfigElem::add_prop( const char* propname, const char* propval )
504 {
505  properties.insert( make_pair( std::string( propname ), std::string( propval ) ) );
506 }
507 void VectorConfigElem::add_prop( const char* propname, const char* propval )
508 {
509  ConfigProperty* prop;
510 
511  prop = new ConfigProperty( propname, propval );
512 
513  properties.push_back( prop );
514 }
515 
516 void ConfigElem::add_prop( const char* propname, unsigned short sval )
517 {
518  OSTRINGSTREAM os;
519  os << sval;
520 
521  properties.insert( make_pair( std::string( propname ), OSTRINGSTREAM_STR( os ) ) );
522 }
523 void ConfigElem::add_prop( const char* propname, short sval )
524 {
525  OSTRINGSTREAM os;
526  os << sval;
527 
528  properties.insert( make_pair( std::string( propname ), OSTRINGSTREAM_STR( os ) ) );
529 }
530 
531 void VectorConfigElem::add_prop( const char* propname, unsigned short sval )
532 {
533  ConfigProperty* prop;
534  OSTRINGSTREAM os;
535  os << sval;
536 
537  prop = new ConfigProperty( propname, OSTRINGSTREAM_STR( os ) );
538 
539  properties.push_back( prop );
540 }
541 
542 void ConfigElem::add_prop( const char* propname, unsigned int lval )
543 {
544  OSTRINGSTREAM os;
545  os << lval;
546 
547  properties.insert( make_pair( std::string( propname ), OSTRINGSTREAM_STR( os ) ) );
548 }
549 void VectorConfigElem::add_prop( const char* propname, unsigned int lval )
550 {
551  ConfigProperty* prop;
552  OSTRINGSTREAM os;
553  os << lval;
554 
555  prop = new ConfigProperty( propname, OSTRINGSTREAM_STR( os ) );
556 
557  properties.push_back( prop );
558 }
559 
560 bool VectorConfigElem::remove_first_prop( std::string* propname, std::string* value )
561 {
562  if ( properties.empty() )
563  return false;
564 
565  ConfigProperty* prop = properties.front();
566  *propname = prop->name_;
567  *value = prop->value_;
568  delete prop;
569  properties.erase( properties.begin() );
570  return true;
571 }
572 
573 ConfigFile::ConfigFile( const char* i_filename, const char* allowed_types_str )
574  : _filename( "<n/a>" ),
575  _modified( 0 ),
577  ifs(),
578 #else
579  fp( NULL ),
580 #endif
581  _element_line_start( 0 ),
582  _cur_line( 0 )
583 {
584  init( i_filename, allowed_types_str );
585 }
586 
587 ConfigFile::ConfigFile( const std::string& i_filename, const char* allowed_types_str )
588  : _filename( "<n/a>" ),
589  _modified( 0 ),
591  ifs(),
592 #else
593  fp( NULL ),
594 #endif
595  _element_line_start( 0 ),
596  _cur_line( 0 )
597 {
598  init( i_filename.c_str(), allowed_types_str );
599 }
600 
601 void ConfigFile::init( const char* i_filename, const char* allowed_types_str )
602 {
603  if ( i_filename )
604  {
605  open( i_filename );
606  }
607 
608  if ( allowed_types_str != NULL )
609  {
610  ISTRINGSTREAM is( allowed_types_str );
611  std::string tag;
612  while ( is >> tag )
613  {
614  allowed_types_.insert( tag.c_str() );
615  }
616  }
617 }
618 
619 const std::string& ConfigFile::filename() const
620 {
621  return _filename;
622 }
623 time_t ConfigFile::modified() const
624 {
625  return _modified;
626 }
628 {
629  return _element_line_start;
630 }
631 
632 void ConfigFile::open( const char* i_filename )
633 {
634  _filename = i_filename;
635 
636 #if CFGFILE_USES_IOSTREAMS
637  ifs.open( i_filename, ios::in );
638 
639  if ( !ifs.is_open() )
640  {
641  ERROR_PRINT << "Unable to open configuration file " << _filename << "\n";
642  throw std::runtime_error( std::string( "Unable to open configuration file " ) + _filename );
643  }
644 #else
645  fp = fopen( i_filename, "rt" );
646  if ( !fp )
647  {
648  ERROR_PRINT << "Unable to open configuration file " << _filename << "\n";
649  throw std::runtime_error( std::string( "Unable to open configuration file " ) + _filename );
650  }
651 #endif
652 
653  struct stat cfgstat;
654  stat( i_filename, &cfgstat );
655  _modified = cfgstat.st_mtime;
656 }
657 
659 {
660 #if !CFGFILE_USES_IOSTREAMS
661  if ( fp )
662  fclose( fp );
663  fp = NULL;
664 #endif
665 }
666 
667 #if !CFGFILE_USES_IOSTREAMS
668 char ConfigFile::buffer[1024];
669 #endif
670 
671 #if CFGFILE_USES_IOSTREAMS
672 // returns true if ended on a }, false if ended on EOF.
674 {
675  std::string strbuf;
676  std::string propname, propvalue;
677  while ( getline( ifs, strbuf ) ) // get
678  {
679  ++cur_line;
680 
681  ISTRINGSTREAM is( strbuf );
682 
683 
684  splitnamevalue( strbuf, propname, propvalue );
685 
686  if ( propname.empty() || // empty line
687  commentline( propname ) )
688  {
689  continue;
690  }
691 
692  if ( propname == "}" )
693  return true;
694 
695  if ( propvalue[0] == '\"' )
696  convertquotedstring( propvalue );
697 
698  ConfigProperty* prop = new ConfigProperty( &propname, &propvalue );
699  elem.properties.push_back( prop );
700  }
701  return false;
702 }
703 
704 
705 bool ConfigFile::_read( ConfigElem& elem )
706 {
707  while ( !elem.properties.empty() )
708  {
709  delete elem.properties.back();
710  elem.properties.pop_back();
711  }
712  elem.type_ = "";
713  elem.rest_ = "";
714 
715  element_line_start = 0;
716 
717  std::string strbuf;
718  while ( getline( ifs, strbuf ) )
719  {
720  ++cur_line;
721 
722  string type, rest;
723  splitnamevalue( strbuf, type, rest );
724 
725  if ( type.empty() || // empty line
726  commentline( type ) )
727  {
728  continue;
729  }
730 
731  element_line_start = cur_line;
732 
733  elem.type_ = type;
734 
735  if ( !allowed_types_.empty() )
736  {
737  if ( allowed_types_.find( type.c_str() ) == allowed_types_.end() )
738  {
739  e_ostringstream os;
740  os << "Unexpected type '" << type << "'" << endl;
741  os << "\tValid types are:";
742  for ( AllowedTypesCont::const_iterator itr = allowed_types_.begin();
743  itr != allowed_types_.end(); ++itr )
744  {
745  os << " " << ( *itr ).c_str();
746  }
747  throw std::runtime_error( os.e_str() );
748  }
749  }
750 
751  elem.rest_ = rest;
752 
753  if ( !getline( ifs, strbuf ) )
754  throw std::runtime_error( "File ends after element type -- expected a '{'" );
755  ++cur_line;
756 
757  if ( strbuf.empty() || strbuf[0] != '{' )
758  {
759  throw std::runtime_error( "Expected '{' on a blank line after element type" );
760  }
761 
762  if ( read_properties( elem ) )
763  return true;
764  else
765  throw std::runtime_error( "Expected '}' on a blank line after element properties" );
766  }
767  return false;
768 }
769 #else
770 
771 bool ConfigFile::readline( std::string& strbuf )
772 {
773  if ( !fgets( buffer, sizeof buffer, fp ) )
774  return false;
775 
776  strbuf = "";
777 
778  do
779  {
780  char* nl = strchr( buffer, '\n' );
781  if ( nl )
782  {
783  if ( nl != buffer && *( nl - 1 ) == '\r' )
784  --nl;
785  *nl = '\0';
786  strbuf += buffer;
787  return true;
788  }
789  else
790  {
791  strbuf += buffer;
792  }
793  } while ( fgets( buffer, sizeof buffer, fp ) );
794 
795  return true;
796 }
797 
798 // returns true if ended on a }, false if ended on EOF.
800 {
801  static std::string strbuf;
802  static std::string propname, propvalue;
803  while ( readline( strbuf ) )
804  {
805  ++_cur_line;
806 
807  ISTRINGSTREAM is( strbuf );
808 
809 
810  splitnamevalue( strbuf, propname, propvalue );
811 
812  if ( propname.empty() || // empty line
813  commentline( propname ) )
814  {
815  continue;
816  }
817 
818  if ( propname == "}" )
819  return true;
820 
821  if ( propvalue[0] == '\"' )
822  {
823  decodequotedstring( propvalue );
824  }
825 
826  elem.properties.insert( make_pair( propname, propvalue ) );
827  }
828  return false;
829 }
831 {
832  static std::string strbuf;
833  static std::string propname, propvalue;
834  while ( readline( strbuf ) )
835  {
836  ++_cur_line;
837 
838  ISTRINGSTREAM is( strbuf );
839 
840 
841  splitnamevalue( strbuf, propname, propvalue );
842 
843  if ( propname.empty() || // empty line
844  commentline( propname ) )
845  {
846  continue;
847  }
848 
849  if ( propname == "}" )
850  return true;
851 
852  if ( propvalue[0] == '\"' )
853  {
854  decodequotedstring( propvalue );
855  }
856 
857  auto prop = new ConfigProperty( &propname, &propvalue );
858  elem.properties.push_back( prop );
859  }
860  return false;
861 }
862 
863 
865 {
866  elem.properties.clear();
867 
868  elem.type_ = "";
869  elem.rest_ = "";
870 
872 
873  std::string strbuf;
874  while ( readline( strbuf ) )
875  {
876  ++_cur_line;
877 
878  std::string type, rest;
879  splitnamevalue( strbuf, type, rest );
880 
881  if ( type.empty() || // empty line
882  commentline( type ) )
883  {
884  continue;
885  }
886 
888 
889  elem.type_ = type;
890 
891  if ( !allowed_types_.empty() )
892  {
893  if ( allowed_types_.find( type.c_str() ) == allowed_types_.end() )
894  {
895  OSTRINGSTREAM os;
896  os << "Unexpected type '" << type << "'" << std::endl;
897  os << "\tValid types are:";
898  for ( const auto& allowed : allowed_types_ )
899  {
900  os << " " << allowed.c_str();
901  }
902  throw std::runtime_error( OSTRINGSTREAM_STR( os ) );
903  }
904  }
905 
906  elem.rest_ = rest;
907 
908  if ( !fgets( buffer, sizeof buffer, fp ) )
909  throw std::runtime_error( "File ends after element type -- expected a '{'" );
910  strbuf = buffer;
911  ++_cur_line;
912 
913  if ( strbuf.empty() || strbuf[0] != '{' )
914  {
915  throw std::runtime_error( "Expected '{' on a blank line after element type" );
916  }
917 
918  if ( read_properties( elem ) )
919  return true;
920  else
921  throw std::runtime_error( "Expected '}' on a blank line after element properties" );
922  }
923  return false;
924 }
925 
927 {
928  while ( !elem.properties.empty() )
929  {
930  delete elem.properties.back();
931  elem.properties.pop_back();
932  }
933  elem.type_ = "";
934  elem.rest_ = "";
935 
937 
938  std::string strbuf;
939  while ( readline( strbuf ) )
940  {
941  ++_cur_line;
942 
943  std::string type, rest;
944  splitnamevalue( strbuf, type, rest );
945 
946  if ( type.empty() || // empty line
947  commentline( type ) )
948  {
949  continue;
950  }
951 
953 
954  elem.type_ = type;
955 
956  if ( !allowed_types_.empty() )
957  {
958  if ( allowed_types_.find( type.c_str() ) == allowed_types_.end() )
959  {
960  OSTRINGSTREAM os;
961  os << "Unexpected type '" << type << "'" << std::endl;
962  os << "\tValid types are:";
963  for ( const auto& allowed : allowed_types_ )
964  {
965  os << " " << allowed.c_str();
966  }
967  throw std::runtime_error( OSTRINGSTREAM_STR( os ) );
968  }
969  }
970 
971  elem.rest_ = rest;
972 
973  if ( !fgets( buffer, sizeof buffer, fp ) )
974  throw std::runtime_error( "File ends after element type -- expected a '{'" );
975  strbuf = buffer;
976  ++_cur_line;
977 
978  if ( strbuf.empty() || strbuf[0] != '{' )
979  {
980  throw std::runtime_error( "Expected '{' on a blank line after element type" );
981  }
982 
983  if ( read_properties( elem ) )
984  return true;
985  else
986  throw std::runtime_error( "Expected '}' on a blank line after element properties" );
987  }
988  return false;
989 }
990 
991 
992 #endif
993 
994 void ConfigFile::display_error( const std::string& msg, bool show_curline,
995  const ConfigElemBase* elem, bool error ) const
996 {
997  bool showed_elem_line = false;
998  fmt::Writer tmp;
999  tmp << ( error ? "Error" : "Warning" ) << " reading configuration file " << _filename << ":\n"
1000  << "\t" << msg << "\n";
1001 
1002  if ( elem != NULL )
1003  {
1004  if ( strlen( elem->type() ) > 0 )
1005  {
1006  tmp << "\tElement: " << elem->type() << " " << elem->rest();
1007  if ( _element_line_start )
1008  tmp << ", found on line " << _element_line_start;
1009  tmp << "\n";
1010  showed_elem_line = true;
1011  }
1012  }
1013 
1014  if ( show_curline )
1015  tmp << "\tNear line: " << _cur_line << "\n";
1016  if ( _element_line_start && !showed_elem_line )
1017  tmp << "\tElement started on line: " << _element_line_start << "\n";
1018  ERROR_PRINT << tmp.str();
1019 }
1020 
1022 {
1023  try
1024  {
1025  throw;
1026  }
1027  catch ( const char* msg )
1028  {
1029  display_error( msg );
1030  }
1031  catch ( std::string& str )
1032  {
1033  display_error( str );
1034  }
1035  catch ( std::exception& ex )
1036  {
1037  display_error( ex.what() );
1038  }
1039  catch ( ... )
1040  {
1041  display_error( "(Generic exception)" );
1042  }
1043 
1044  throw std::runtime_error( "Configuration file error." );
1045 }
1046 
1048 {
1049  try
1050  {
1051  elem._source = this;
1052  return _read( elem );
1053  }
1054  catch ( ... )
1055  {
1056  display_and_rethrow_exception(); // throws and doesn't return
1057  }
1058 }
1059 
1061 {
1062  try
1063  {
1064  elem._source = this;
1065  if ( read_properties( elem ) )
1066  throw std::runtime_error( "unexpected '}' in file" );
1067  }
1068  catch ( ... )
1069  {
1071  }
1072 }
1073 
1074 void StubConfigSource::display_error( const std::string& msg, bool /*show_curline*/,
1075  const ConfigElemBase* /*elem*/, bool error ) const
1076 {
1077  ERROR_PRINT << ( error ? "Error" : "Warning" ) << " reading configuration element:"
1078  << "\t" << msg << "\n";
1079 }
1080 }
1081 }
virtual ~ConfigFile()
Definition: cfgfile.cpp:658
bool remove_first_prop(std::string *propname, std::string *value)
Definition: cfgfile.cpp:113
void warn_with_line(const std::string &errmsg) const
Definition: cfgfile.cpp:317
virtual void display_error(const std::string &msg, bool show_curline=true, const ConfigElemBase *elem=NULL, bool error=true) const =0
std::string remove_string(const char *propname)
Definition: cfgfile.cpp:394
virtual ~ConfigElem()
Definition: cfgfile.cpp:68
void clear_prop(const char *propname)
Definition: cfgfile.cpp:496
float remove_float(const char *propname, float dflt)
Definition: cfgfile.cpp:449
void splitnamevalue(const std::string &istr, std::string &propname, std::string &propvalue)
Definition: strutil.cpp:107
void get_prop(const char *propname, unsigned int *plong) const
Definition: cfgfile.cpp:198
void add_prop(const char *propname, const char *str)
Definition: cfgfile.cpp:503
const std::string & filename() const
Definition: cfgfile.cpp:619
bool readline(std::string &strbuf)
Definition: cfgfile.cpp:771
unsigned int remove_ulong(const char *propname)
Definition: cfgfile.cpp:474
int remove_int(const char *propname)
Definition: cfgfile.cpp:353
void init(const char *i_filename, const char *allowed_types_str)
Definition: cfgfile.cpp:601
#define OSTRINGSTREAM_STR(x)
Definition: stlutil.h:76
#define CFGFILE_USES_IOSTREAMS
Definition: cfgfile.h:12
bool read_properties(ConfigElem &elem)
Definition: cfgfile.cpp:799
bool remove_first_prop(std::string *propname, std::string *value)
Definition: cfgfile.cpp:560
void readraw(ConfigElem &elem)
Definition: cfgfile.cpp:1060
void warn(const std::string &errmsg) const
Definition: cfgfile.cpp:311
double remove_double(const char *propname, double dflt)
Definition: cfgfile.cpp:461
const char * rest() const
Definition: cfgfile.cpp:84
POL_NORETURN void display_and_rethrow_exception()
Definition: cfgfile.cpp:1021
static char buffer[1024]
Definition: cfgfile.h:83
void add_prop(const char *propname, const char *str)
Definition: cfgfile.cpp:507
POL_NORETURN void throw_error(const std::string &errmsg) const
Definition: cfgfile.cpp:298
unsigned element_line_start() const
Definition: cfgfile.cpp:627
ConfigFile(const char *filename=NULL, const char *allowed_types=NULL)
Definition: cfgfile.cpp:573
void set_type(const char *newtype)
Definition: cfgfile.cpp:94
virtual size_t estimateSize() const POL_OVERRIDE
Definition: cfgfile.cpp:70
bool read_prop(const char *propname, std::string *value) const
Definition: cfgfile.cpp:185
bool has_prop(const char *propname) const
Definition: cfgfile.cpp:129
std::string _filename
Definition: cfgfile.h:77
POL_NORETURN void prop_not_found(const char *propname) const
Definition: cfgfile.cpp:323
#define OSTRINGSTREAM
Definition: stlutil.h:75
virtual size_t estimateSize() const
Definition: cfgfile.cpp:61
std::string read_string(const char *propname) const
Definition: cfgfile.cpp:408
void dummy()
Definition: testmisc.cpp:23
POL_NORETURN void throw_error(const std::string &errmsg) const
Definition: cfgfile.cpp:304
void decodequotedstring(std::string &str)
Definition: strutil.cpp:167
AllowedTypesCont allowed_types_
Definition: cfgfile.h:89
void open(const char *i_filename)
Definition: cfgfile.cpp:632
bool remove_prop(const char *propname, std::string *value)
Definition: cfgfile.cpp:141
virtual void display_error(const std::string &msg, bool show_curline, const ConfigElemBase *elem, bool error) const POL_OVERRIDE
Definition: cfgfile.cpp:1074
virtual void display_error(const std::string &msg, bool show_curline=true, const ConfigElemBase *elem=NULL, bool error=true) const POL_OVERRIDE
Definition: cfgfile.cpp:994
bool read_prop(const char *propname, std::string *value) const
Definition: cfgfile.cpp:172
#define ISTRINGSTREAM
Definition: stlutil.h:73
bool type_is(const char *name) const
Definition: cfgfile.cpp:108
bool has_prop(const char *propname) const
Definition: cfgfile.cpp:125
bool _read(ConfigElem &elem)
Definition: cfgfile.cpp:864
unsigned short remove_ushort(const char *propname)
Definition: cfgfile.cpp:331
std::string name
Definition: osmod.cpp:943
bool remove_prop(const char *propname, std::string *value)
Definition: cfgfile.cpp:155
void set_source(const ConfigElem &elem)
Definition: cfgfile.cpp:99
std::string value_
Definition: cfgelem.h:31
#define ERROR_PRINT
Definition: logfacility.h:230
bool read(ConfigElem &elem)
Definition: cfgfile.cpp:1047
const char * type() const
Definition: cfgfile.cpp:79
void set_rest(const char *newrest)
Definition: cfgfile.cpp:89
Definition: berror.cpp:12
unsigned remove_unsigned(const char *propname)
Definition: cfgfile.cpp:373
bool remove_bool(const char *propname)
Definition: cfgfile.cpp:439
time_t modified() const
Definition: cfgfile.cpp:623
const ConfigSource * _source
Definition: cfgelem.h:54