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 13 #include "boost/property_tree/ptree.hpp" 14 #include "boost/property_tree/detail/info_parser_utils.hpp" 15 #include <string> 16 17 namespace boost { namespace property_tree { namespace info_parser 18 { 19 template<class Ch> write_info_indent(std::basic_ostream<Ch> & stream,int indent,const info_writer_settings<Ch> & settings)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 28 // Create necessary escape sequences from illegal characters 29 template<class Ch> create_escapes(const std::basic_string<Ch> & s)30 std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s) 31 { 32 std::basic_string<Ch> result; 33 typename std::basic_string<Ch>::const_iterator b = s.begin(); 34 typename std::basic_string<Ch>::const_iterator e = s.end(); 35 while (b != e) 36 { 37 if (*b == Ch('\0')) result += Ch('\\'), result += Ch('0'); 38 else if (*b == Ch('\a')) result += Ch('\\'), result += Ch('a'); 39 else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b'); 40 else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f'); 41 else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n'); 42 else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r'); 43 else if (*b == Ch('\v')) result += Ch('\\'), result += Ch('v'); 44 else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"'); 45 else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\'); 46 else 47 result += *b; 48 ++b; 49 } 50 return result; 51 } 52 53 template<class Ch> is_simple_key(const std::basic_string<Ch> & key)54 bool is_simple_key(const std::basic_string<Ch> &key) 55 { 56 const static std::basic_string<Ch> chars = convert_chtype<Ch, char>(" \t{};\n\""); 57 return !key.empty() && key.find_first_of(chars) == key.npos; 58 } 59 60 template<class Ch> is_simple_data(const std::basic_string<Ch> & data)61 bool is_simple_data(const std::basic_string<Ch> &data) 62 { 63 const static std::basic_string<Ch> chars = convert_chtype<Ch, char>(" \t{};\n\""); 64 return !data.empty() && data.find_first_of(chars) == data.npos; 65 } 66 67 template<class Ptree> write_info_helper(std::basic_ostream<typename Ptree::key_type::value_type> & stream,const Ptree & pt,int indent,const info_writer_settings<typename Ptree::key_type::value_type> & settings)68 void write_info_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 69 const Ptree &pt, 70 int indent, 71 const info_writer_settings<typename Ptree::key_type::value_type> &settings) 72 { 73 74 // Character type 75 typedef typename Ptree::key_type::value_type Ch; 76 77 // Write data 78 if (indent >= 0) 79 { 80 if (!pt.data().empty()) 81 { 82 std::basic_string<Ch> data = create_escapes(pt.template get_value<std::basic_string<Ch> >()); 83 if (is_simple_data(data)) 84 stream << Ch(' ') << data << Ch('\n'); 85 else 86 stream << Ch(' ') << Ch('\"') << data << Ch('\"') << Ch('\n'); 87 } 88 else if (pt.empty()) 89 stream << Ch(' ') << Ch('\"') << Ch('\"') << Ch('\n'); 90 else 91 stream << Ch('\n'); 92 } 93 94 // Write keys 95 if (!pt.empty()) 96 { 97 98 // Open brace 99 if (indent >= 0) 100 { 101 write_info_indent( stream, indent, settings); 102 stream << Ch('{') << Ch('\n'); 103 } 104 105 // Write keys 106 typename Ptree::const_iterator it = pt.begin(); 107 for (; it != pt.end(); ++it) 108 { 109 110 // Output key 111 std::basic_string<Ch> key = create_escapes(it->first); 112 write_info_indent( stream, indent+1, settings); 113 if (is_simple_key(key)) 114 stream << key; 115 else 116 stream << Ch('\"') << key << Ch('\"'); 117 118 // Output data and children 119 write_info_helper(stream, it->second, indent + 1, settings); 120 121 } 122 123 // Close brace 124 if (indent >= 0) 125 { 126 write_info_indent( stream, indent, settings); 127 stream << Ch('}') << Ch('\n'); 128 } 129 130 } 131 } 132 133 // Write ptree to info stream 134 template<class Ptree> write_info_internal(std::basic_ostream<typename Ptree::key_type::value_type> & stream,const Ptree & pt,const std::string & filename,const info_writer_settings<typename Ptree::key_type::value_type> & settings)135 void write_info_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 136 const Ptree &pt, 137 const std::string &filename, 138 const info_writer_settings<typename Ptree::key_type::value_type> &settings) 139 { 140 write_info_helper(stream, pt, -1, settings); 141 if (!stream.good()) 142 BOOST_PROPERTY_TREE_THROW(info_parser_error("write error", filename, 0)); 143 } 144 145 } } } 146 147 #endif 148