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