/xbmc/visualizations/XBMCProjectM/libprojectM/ConfigFile.cpp

http://github.com/xbmc/xbmc · C++ · 142 lines · 94 code · 29 blank · 19 comment · 24 complexity · efd67b25a2b2542b64796fd3f87309b2 MD5 · raw file

  1. // ConfigFile.cpp
  2. #include "ConfigFile.h"
  3. using std::string;
  4. ConfigFile::ConfigFile( string filename, string delimiter,
  5. string comment, string sentry )
  6. : myDelimiter(delimiter), myComment(comment), mySentry(sentry)
  7. {
  8. // Construct a ConfigFile, getting keys and values from given file
  9. std::ifstream in( filename.c_str() );
  10. if( !in ) throw file_not_found( filename );
  11. in >> (*this);
  12. }
  13. ConfigFile::ConfigFile()
  14. : myDelimiter( string(1,'=') ), myComment( string(1,'#') )
  15. {
  16. // Construct a ConfigFile without a file; empty
  17. }
  18. void ConfigFile::remove( const string& key )
  19. {
  20. // Remove key and its value
  21. myContents.erase( myContents.find( key ) );
  22. return;
  23. }
  24. bool ConfigFile::keyExists( const string& key ) const
  25. {
  26. // Indicate whether key is found
  27. mapci p = myContents.find( key );
  28. return ( p != myContents.end() );
  29. }
  30. /* static */
  31. void ConfigFile::trim( string& s )
  32. {
  33. // Remove leading and trailing whitespace
  34. static const char whitespace[] = " \n\t\v\r\f";
  35. s.erase( 0, s.find_first_not_of(whitespace) );
  36. s.erase( s.find_last_not_of(whitespace) + 1U );
  37. }
  38. std::ostream& operator<<( std::ostream& os, const ConfigFile& cf )
  39. {
  40. // Save a ConfigFile to os
  41. for( ConfigFile::mapci p = cf.myContents.begin();
  42. p != cf.myContents.end();
  43. ++p )
  44. {
  45. os << p->first << " " << cf.myDelimiter << " ";
  46. os << p->second << std::endl;
  47. }
  48. return os;
  49. }
  50. std::istream& operator>>( std::istream& is, ConfigFile& cf )
  51. {
  52. // Load a ConfigFile from is
  53. // Read in keys and values, keeping internal whitespace
  54. typedef string::size_type pos;
  55. const string& delim = cf.myDelimiter; // separator
  56. const string& comm = cf.myComment; // comment
  57. const string& sentry = cf.mySentry; // end of file sentry
  58. const pos skip = delim.length(); // length of separator
  59. string nextline = ""; // might need to read ahead to see where value ends
  60. while( is || nextline.length() > 0 )
  61. {
  62. // Read an entire line at a time
  63. string line;
  64. if( nextline.length() > 0 )
  65. {
  66. line = nextline; // we read ahead; use it now
  67. nextline = "";
  68. }
  69. else
  70. {
  71. std::getline( is, line );
  72. }
  73. // Ignore comments
  74. line = line.substr( 0, line.find(comm) );
  75. // Check for end of file sentry
  76. if( sentry != "" && line.find(sentry) != string::npos ) return is;
  77. // Parse the line if it contains a delimiter
  78. pos delimPos = line.find( delim );
  79. if( delimPos < string::npos )
  80. {
  81. // Extract the key
  82. string key = line.substr( 0, delimPos );
  83. line.replace( 0, delimPos+skip, "" );
  84. // See if value continues on the next line
  85. // Stop at blank line, next line with a key, end of stream,
  86. // or end of file sentry
  87. bool terminate = false;
  88. while( !terminate && is )
  89. {
  90. std::getline( is, nextline );
  91. terminate = true;
  92. string nlcopy = nextline;
  93. ConfigFile::trim(nlcopy);
  94. if( nlcopy == "" ) continue;
  95. nextline = nextline.substr( 0, nextline.find(comm) );
  96. if( nextline.find(delim) != string::npos )
  97. continue;
  98. if( sentry != "" && nextline.find(sentry) != string::npos )
  99. continue;
  100. nlcopy = nextline;
  101. ConfigFile::trim(nlcopy);
  102. if( nlcopy != "" ) line += "\n";
  103. line += nextline;
  104. terminate = false;
  105. }
  106. // Store key and value
  107. ConfigFile::trim(key);
  108. ConfigFile::trim(line);
  109. cf.myContents[key] = line; // overwrites if key is repeated
  110. }
  111. }
  112. return is;
  113. }