info_parser_write.hpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // ----------------------------------------------------------------------------
  2. // Copyright (C) 2002-2006 Marcin Kalicinski
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // For more information, see www.boost.org
  9. // ----------------------------------------------------------------------------
  10. #ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_WRITE_HPP_INCLUDED
  11. #define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_WRITE_HPP_INCLUDED
  12. #include <boost/property_tree/detail/info_parser_error.hpp>
  13. #include <boost/property_tree/detail/info_parser_utils.hpp>
  14. #include <boost/property_tree/detail/info_parser_writer_settings.hpp>
  15. #include <boost/property_tree/ptree.hpp>
  16. #include <string>
  17. namespace boost { namespace property_tree { namespace info_parser
  18. {
  19. template<class Ch>
  20. void write_info_indent(std::basic_ostream<Ch> &stream,
  21. int indent,
  22. const info_writer_settings<Ch> &settings
  23. )
  24. {
  25. stream << std::basic_string<Ch>(indent * settings.indent_count, settings.indent_char);
  26. }
  27. // Create necessary escape sequences from illegal characters
  28. template<class Ch>
  29. std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
  30. {
  31. std::basic_string<Ch> result;
  32. typename std::basic_string<Ch>::const_iterator b = s.begin();
  33. typename std::basic_string<Ch>::const_iterator e = s.end();
  34. while (b != e)
  35. {
  36. if (*b == Ch('\0')) result += Ch('\\'), result += Ch('0');
  37. else if (*b == Ch('\a')) result += Ch('\\'), result += Ch('a');
  38. else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
  39. else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
  40. else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
  41. else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
  42. else if (*b == Ch('\v')) result += Ch('\\'), result += Ch('v');
  43. else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
  44. else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
  45. else
  46. result += *b;
  47. ++b;
  48. }
  49. return result;
  50. }
  51. template<class Ch>
  52. bool is_simple_key(const std::basic_string<Ch> &key)
  53. {
  54. const static std::basic_string<Ch> chars = convert_chtype<Ch, char>(" \t{};\n\"");
  55. return !key.empty() && key.find_first_of(chars) == key.npos;
  56. }
  57. template<class Ch>
  58. bool is_simple_data(const std::basic_string<Ch> &data)
  59. {
  60. const static std::basic_string<Ch> chars = convert_chtype<Ch, char>(" \t{};\n\"");
  61. return !data.empty() && data.find_first_of(chars) == data.npos;
  62. }
  63. template<class Ptree>
  64. void write_info_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
  65. const Ptree &pt,
  66. int indent,
  67. const info_writer_settings<typename Ptree::key_type::value_type> &settings)
  68. {
  69. // Character type
  70. typedef typename Ptree::key_type::value_type Ch;
  71. // Write data
  72. if (indent >= 0)
  73. {
  74. if (!pt.data().empty())
  75. {
  76. std::basic_string<Ch> data = create_escapes(pt.template get_value<std::basic_string<Ch> >());
  77. if (is_simple_data(data))
  78. stream << Ch(' ') << data << Ch('\n');
  79. else
  80. stream << Ch(' ') << Ch('\"') << data << Ch('\"') << Ch('\n');
  81. }
  82. else if (pt.empty())
  83. stream << Ch(' ') << Ch('\"') << Ch('\"') << Ch('\n');
  84. else
  85. stream << Ch('\n');
  86. }
  87. // Write keys
  88. if (!pt.empty())
  89. {
  90. // Open brace
  91. if (indent >= 0)
  92. {
  93. write_info_indent( stream, indent, settings);
  94. stream << Ch('{') << Ch('\n');
  95. }
  96. // Write keys
  97. typename Ptree::const_iterator it = pt.begin();
  98. for (; it != pt.end(); ++it)
  99. {
  100. // Output key
  101. std::basic_string<Ch> key = create_escapes(it->first);
  102. write_info_indent( stream, indent+1, settings);
  103. if (is_simple_key(key))
  104. stream << key;
  105. else
  106. stream << Ch('\"') << key << Ch('\"');
  107. // Output data and children
  108. write_info_helper(stream, it->second, indent + 1, settings);
  109. }
  110. // Close brace
  111. if (indent >= 0)
  112. {
  113. write_info_indent( stream, indent, settings);
  114. stream << Ch('}') << Ch('\n');
  115. }
  116. }
  117. }
  118. // Write ptree to info stream
  119. template<class Ptree>
  120. void write_info_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
  121. const Ptree &pt,
  122. const std::string &filename,
  123. const info_writer_settings<typename Ptree::key_type::value_type> &settings)
  124. {
  125. write_info_helper(stream, pt, -1, settings);
  126. stream.flush();
  127. if (!stream.good())
  128. BOOST_PROPERTY_TREE_THROW(info_parser_error("write error", filename, 0));
  129. }
  130. } } }
  131. #endif