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