1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3 
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 #if !defined(BOOST_SPIRIT_INFO_NOVEMBER_22_2008_1132AM)
8 #define BOOST_SPIRIT_INFO_NOVEMBER_22_2008_1132AM
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/variant/variant.hpp>
15 #include <boost/variant/recursive_variant.hpp>
16 #include <boost/variant/apply_visitor.hpp>
17 #include <boost/foreach.hpp>
18 #include <boost/spirit/home/support/utf8.hpp>
19 #include <list>
20 #include <iterator>
21 #include <utility>
22 
23 namespace boost { namespace spirit
24 {
25     // info provides information about a component. Each component
26     // has a what member function that returns an info object.
27     // strings in the info object are assumed to be encoded as UTF8
28     // for uniformity.
29     struct info
30     {
31         struct nil_ {};
32 
33         typedef
34             boost::variant<
35                 nil_
36               , utf8_string
37               , recursive_wrapper<info>
38               , recursive_wrapper<std::pair<info, info> >
39               , recursive_wrapper<std::list<info> >
40             >
41         value_type;
42 
infoboost::spirit::info43         explicit info(utf8_string const& tag_)
44           : tag(tag_), value(nil_()) {}
45 
46         template <typename T>
infoboost::spirit::info47         info(utf8_string const& tag_, T const& value_)
48           : tag(tag_), value(value_) {}
49 
infoboost::spirit::info50         info(utf8_string const& tag_, char value_)
51           : tag(tag_), value(utf8_string(1, value_)) {}
52 
infoboost::spirit::info53         info(utf8_string const& tag_, wchar_t value_)
54           : tag(tag_), value(to_utf8(value_)) {}
55 
infoboost::spirit::info56         info(utf8_string const& tag_, ucs4_char value_)
57           : tag(tag_), value(to_utf8(value_)) {}
58 
59         template <typename Char>
infoboost::spirit::info60         info(utf8_string const& tag_, Char const* str)
61           : tag(tag_), value(to_utf8(str)) {}
62 
63         template <typename Char, typename Traits, typename Allocator>
infoboost::spirit::info64         info(utf8_string const& tag_
65               , std::basic_string<Char, Traits, Allocator> const& str)
66           : tag(tag_), value(to_utf8(str)) {}
67 
68         utf8_string tag;
69         value_type value;
70     };
71 
72     template <typename Callback>
73     struct basic_info_walker
74     {
75         typedef void result_type;
76         typedef basic_info_walker<Callback> this_type;
77 
basic_info_walkerboost::spirit::basic_info_walker78         basic_info_walker(Callback& callback_, utf8_string const& tag_, int depth_)
79           : callback(callback_), tag(tag_), depth(depth_) {}
80 
operator ()boost::spirit::basic_info_walker81         void operator()(info::nil_) const
82         {
83             callback.element(tag, "", depth);
84         }
85 
operator ()boost::spirit::basic_info_walker86         void operator()(utf8_string const& str) const
87         {
88             callback.element(tag, str, depth);
89         }
90 
operator ()boost::spirit::basic_info_walker91         void operator()(info const& what) const
92         {
93             boost::apply_visitor(
94                 this_type(callback, what.tag, depth+1), what.value);
95         }
96 
operator ()boost::spirit::basic_info_walker97         void operator()(std::pair<info, info> const& pair) const
98         {
99             callback.element(tag, "", depth);
100             boost::apply_visitor(
101                 this_type(callback, pair.first.tag, depth+1), pair.first.value);
102             boost::apply_visitor(
103                 this_type(callback, pair.second.tag, depth+1), pair.second.value);
104         }
105 
operator ()boost::spirit::basic_info_walker106         void operator()(std::list<info> const& l) const
107         {
108             callback.element(tag, "", depth);
109             BOOST_FOREACH(info const& what, l)
110             {
111                 boost::apply_visitor(
112                     this_type(callback, what.tag, depth+1), what.value);
113             }
114         }
115 
116         Callback& callback;
117         utf8_string const& tag;
118         int depth;
119 
120         // silence MSVC warning C4512: assignment operator could not be generated
121         BOOST_DELETED_FUNCTION(basic_info_walker& operator= (basic_info_walker const&))
122     };
123 
124     // bare-bones print support
125     template <typename Out>
126     struct simple_printer
127     {
128         typedef utf8_string string;
129 
simple_printerboost::spirit::simple_printer130         simple_printer(Out& out_)
131           : out(out_) {}
132 
elementboost::spirit::simple_printer133         void element(string const& tag, string const& value, int /*depth*/) const
134         {
135             if (value == "")
136                 out << '<' << tag << '>';
137             else
138                 out << '"' << value << '"';
139         }
140 
141         Out& out;
142 
143         // silence MSVC warning C4512: assignment operator could not be generated
144         BOOST_DELETED_FUNCTION(simple_printer& operator= (simple_printer const&))
145     };
146 
147     template <typename Out>
operator <<(Out & out,info const & what)148     Out& operator<<(Out& out, info const& what)
149     {
150         simple_printer<Out> pr(out);
151         basic_info_walker<simple_printer<Out> > walker(pr, what.tag, 0);
152         boost::apply_visitor(walker, what.value);
153         return out;
154     }
155 }}
156 
157 #endif
158