Chris@16
|
1 /*
|
Chris@16
|
2 * Copyright Andrey Semashev 2007 - 2013.
|
Chris@16
|
3 * Distributed under the Boost Software License, Version 1.0.
|
Chris@16
|
4 * (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
5 * http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6 */
|
Chris@16
|
7 /*!
|
Chris@16
|
8 * \file formatters/c_decorator.hpp
|
Chris@16
|
9 * \author Andrey Semashev
|
Chris@16
|
10 * \date 18.11.2012
|
Chris@16
|
11 *
|
Chris@16
|
12 * The header contains implementation of C-style character decorators.
|
Chris@16
|
13 */
|
Chris@16
|
14
|
Chris@16
|
15 #ifndef BOOST_LOG_EXPRESSIONS_FORMATTERS_C_DECORATOR_HPP_INCLUDED_
|
Chris@16
|
16 #define BOOST_LOG_EXPRESSIONS_FORMATTERS_C_DECORATOR_HPP_INCLUDED_
|
Chris@16
|
17
|
Chris@16
|
18 #include <limits>
|
Chris@16
|
19 #include <boost/range/iterator_range_core.hpp>
|
Chris@16
|
20 #include <boost/log/detail/config.hpp>
|
Chris@16
|
21 #include <boost/log/detail/snprintf.hpp>
|
Chris@16
|
22 #include <boost/log/expressions/formatters/char_decorator.hpp>
|
Chris@16
|
23 #include <boost/log/detail/header.hpp>
|
Chris@16
|
24
|
Chris@16
|
25 #ifdef BOOST_HAS_PRAGMA_ONCE
|
Chris@16
|
26 #pragma once
|
Chris@16
|
27 #endif
|
Chris@16
|
28
|
Chris@16
|
29 namespace boost {
|
Chris@16
|
30
|
Chris@16
|
31 BOOST_LOG_OPEN_NAMESPACE
|
Chris@16
|
32
|
Chris@16
|
33 namespace expressions {
|
Chris@16
|
34
|
Chris@16
|
35 namespace aux {
|
Chris@16
|
36
|
Chris@16
|
37 template< typename >
|
Chris@16
|
38 struct c_decorator_traits;
|
Chris@16
|
39
|
Chris@16
|
40 #ifdef BOOST_LOG_USE_CHAR
|
Chris@16
|
41 template< >
|
Chris@16
|
42 struct c_decorator_traits< char >
|
Chris@16
|
43 {
|
Chris@16
|
44 static boost::iterator_range< const char* const* > get_patterns()
|
Chris@16
|
45 {
|
Chris@16
|
46 static const char* const patterns[] =
|
Chris@16
|
47 {
|
Chris@16
|
48 "\\", "\a", "\b", "\f", "\n", "\r", "\t", "\v", "'", "\"", "?"
|
Chris@16
|
49 };
|
Chris@16
|
50 return boost::make_iterator_range(patterns);
|
Chris@16
|
51 }
|
Chris@16
|
52 static boost::iterator_range< const char* const* > get_replacements()
|
Chris@16
|
53 {
|
Chris@16
|
54 static const char* const replacements[] =
|
Chris@16
|
55 {
|
Chris@16
|
56 "\\\\", "\\a", "\\b", "\\f", "\\n", "\\r", "\\t", "\\v", "\\'", "\\\"", "\\?"
|
Chris@16
|
57 };
|
Chris@16
|
58 return boost::make_iterator_range(replacements);
|
Chris@16
|
59 }
|
Chris@16
|
60 template< unsigned int N >
|
Chris@16
|
61 static std::size_t print_escaped(char (&buf)[N], char c)
|
Chris@16
|
62 {
|
Chris@16
|
63 return static_cast< std::size_t >(
|
Chris@16
|
64 boost::log::aux::snprintf(buf, N, "\\x%0.2X", static_cast< unsigned int >(static_cast< uint8_t >(c))));
|
Chris@16
|
65 }
|
Chris@16
|
66 };
|
Chris@16
|
67 #endif // BOOST_LOG_USE_CHAR
|
Chris@16
|
68
|
Chris@16
|
69 #ifdef BOOST_LOG_USE_WCHAR_T
|
Chris@16
|
70 template< >
|
Chris@16
|
71 struct c_decorator_traits< wchar_t >
|
Chris@16
|
72 {
|
Chris@16
|
73 static boost::iterator_range< const wchar_t* const* > get_patterns()
|
Chris@16
|
74 {
|
Chris@16
|
75 static const wchar_t* const patterns[] =
|
Chris@16
|
76 {
|
Chris@16
|
77 L"\\", L"\a", L"\b", L"\f", L"\n", L"\r", L"\t", L"\v", L"'", L"\"", L"?"
|
Chris@16
|
78 };
|
Chris@16
|
79 return boost::make_iterator_range(patterns);
|
Chris@16
|
80 }
|
Chris@16
|
81 static boost::iterator_range< const wchar_t* const* > get_replacements()
|
Chris@16
|
82 {
|
Chris@16
|
83 static const wchar_t* const replacements[] =
|
Chris@16
|
84 {
|
Chris@16
|
85 L"\\\\", L"\\a", L"\\b", L"\\f", L"\\n", L"\\r", L"\\t", L"\\v", L"\\'", L"\\\"", L"\\?"
|
Chris@16
|
86 };
|
Chris@16
|
87 return boost::make_iterator_range(replacements);
|
Chris@16
|
88 }
|
Chris@16
|
89 template< unsigned int N >
|
Chris@16
|
90 static std::size_t print_escaped(wchar_t (&buf)[N], wchar_t c)
|
Chris@16
|
91 {
|
Chris@16
|
92 const wchar_t* format;
|
Chris@16
|
93 register unsigned int val;
|
Chris@16
|
94 if (sizeof(wchar_t) == 1)
|
Chris@16
|
95 {
|
Chris@16
|
96 format = L"\\x%0.2X";
|
Chris@16
|
97 val = static_cast< uint8_t >(c);
|
Chris@16
|
98 }
|
Chris@16
|
99 else if (sizeof(wchar_t) == 2)
|
Chris@16
|
100 {
|
Chris@16
|
101 format = L"\\x%0.4X";
|
Chris@16
|
102 val = static_cast< uint16_t >(c);
|
Chris@16
|
103 }
|
Chris@16
|
104 else
|
Chris@16
|
105 {
|
Chris@16
|
106 format = L"\\x%0.8X";
|
Chris@16
|
107 val = static_cast< uint32_t >(c);
|
Chris@16
|
108 }
|
Chris@16
|
109
|
Chris@16
|
110 return static_cast< std::size_t >(boost::log::aux::swprintf(buf, N, format, val));
|
Chris@16
|
111 }
|
Chris@16
|
112 };
|
Chris@16
|
113 #endif // BOOST_LOG_USE_WCHAR_T
|
Chris@16
|
114
|
Chris@16
|
115 template< typename CharT >
|
Chris@16
|
116 struct c_decorator_gen
|
Chris@16
|
117 {
|
Chris@16
|
118 typedef CharT char_type;
|
Chris@16
|
119
|
Chris@16
|
120 template< typename SubactorT >
|
Chris@16
|
121 BOOST_FORCEINLINE char_decorator_actor< SubactorT, pattern_replacer< char_type > > operator[] (SubactorT const& subactor) const
|
Chris@16
|
122 {
|
Chris@16
|
123 typedef c_decorator_traits< char_type > traits_type;
|
Chris@16
|
124 typedef pattern_replacer< char_type > replacer_type;
|
Chris@16
|
125 typedef char_decorator_actor< SubactorT, replacer_type > result_type;
|
Chris@16
|
126 typedef typename result_type::terminal_type terminal_type;
|
Chris@16
|
127 typename result_type::base_type act = {{ terminal_type(subactor, replacer_type(traits_type::get_patterns(), traits_type::get_replacements())) }};
|
Chris@16
|
128 return result_type(act);
|
Chris@16
|
129 }
|
Chris@16
|
130 };
|
Chris@16
|
131
|
Chris@16
|
132 } // namespace aux
|
Chris@16
|
133
|
Chris@16
|
134 /*!
|
Chris@16
|
135 * C-style decorator generator object. The decorator replaces characters with specific meaning in C
|
Chris@16
|
136 * language with the corresponding escape sequences. The generator provides <tt>operator[]</tt> that
|
Chris@16
|
137 * can be used to construct the actual decorator. For example:
|
Chris@16
|
138 *
|
Chris@16
|
139 * <code>
|
Chris@16
|
140 * c_decor[ attr< std::string >("MyAttr") ]
|
Chris@16
|
141 * </code>
|
Chris@16
|
142 *
|
Chris@16
|
143 * For wide-character formatting there is the similar \c wc_decor decorator generator object.
|
Chris@16
|
144 */
|
Chris@16
|
145 #ifdef BOOST_LOG_USE_CHAR
|
Chris@16
|
146 const aux::c_decorator_gen< char > c_decor = {};
|
Chris@16
|
147 #endif
|
Chris@16
|
148 #ifdef BOOST_LOG_USE_WCHAR_T
|
Chris@16
|
149 const aux::c_decorator_gen< wchar_t > wc_decor = {};
|
Chris@16
|
150 #endif
|
Chris@16
|
151
|
Chris@16
|
152 /*!
|
Chris@16
|
153 * The function creates a C-style decorator generator for arbitrary character type.
|
Chris@16
|
154 */
|
Chris@16
|
155 template< typename CharT >
|
Chris@16
|
156 BOOST_FORCEINLINE aux::c_decorator_gen< CharT > make_c_decor()
|
Chris@16
|
157 {
|
Chris@16
|
158 return aux::c_decorator_gen< CharT >();
|
Chris@16
|
159 }
|
Chris@16
|
160
|
Chris@16
|
161 /*!
|
Chris@16
|
162 * A character decorator implementation that escapes all non-prontable and non-ASCII characters
|
Chris@16
|
163 * in the output with C-style escape sequences.
|
Chris@16
|
164 */
|
Chris@16
|
165 template< typename CharT >
|
Chris@16
|
166 class c_ascii_pattern_replacer :
|
Chris@16
|
167 public pattern_replacer< CharT >
|
Chris@16
|
168 {
|
Chris@16
|
169 private:
|
Chris@16
|
170 //! Base type
|
Chris@16
|
171 typedef pattern_replacer< CharT > base_type;
|
Chris@16
|
172
|
Chris@16
|
173 public:
|
Chris@16
|
174 //! Result type
|
Chris@16
|
175 typedef typename base_type::result_type result_type;
|
Chris@16
|
176 //! Character type
|
Chris@16
|
177 typedef typename base_type::char_type char_type;
|
Chris@16
|
178 //! String type
|
Chris@16
|
179 typedef typename base_type::string_type string_type;
|
Chris@16
|
180
|
Chris@16
|
181 private:
|
Chris@16
|
182 //! Traits type
|
Chris@16
|
183 typedef aux::c_decorator_traits< char_type > traits_type;
|
Chris@16
|
184
|
Chris@16
|
185 public:
|
Chris@16
|
186 //! Default constructor
|
Chris@16
|
187 c_ascii_pattern_replacer() : base_type(traits_type::get_patterns(), traits_type::get_replacements())
|
Chris@16
|
188 {
|
Chris@16
|
189 }
|
Chris@16
|
190
|
Chris@16
|
191 //! Applies string replacements starting from the specified position
|
Chris@16
|
192 result_type operator() (string_type& str, typename string_type::size_type start_pos = 0) const
|
Chris@16
|
193 {
|
Chris@16
|
194 base_type::operator() (str, start_pos);
|
Chris@16
|
195
|
Chris@16
|
196 typedef typename string_type::iterator string_iterator;
|
Chris@16
|
197 for (string_iterator it = str.begin() + start_pos, end = str.end(); it != end; ++it)
|
Chris@16
|
198 {
|
Chris@16
|
199 char_type c = *it;
|
Chris@16
|
200 if (c < 0x20 || c > 0x7e)
|
Chris@16
|
201 {
|
Chris@16
|
202 char_type buf[(std::numeric_limits< char_type >::digits + 3) / 4 + 3];
|
Chris@16
|
203 std::size_t n = traits_type::print_escaped(buf, c);
|
Chris@16
|
204 std::size_t pos = it - str.begin();
|
Chris@16
|
205 str.replace(pos, 1, buf, n);
|
Chris@16
|
206 it = str.begin() + n - 1;
|
Chris@16
|
207 end = str.end();
|
Chris@16
|
208 }
|
Chris@16
|
209 }
|
Chris@16
|
210 }
|
Chris@16
|
211 };
|
Chris@16
|
212
|
Chris@16
|
213 namespace aux {
|
Chris@16
|
214
|
Chris@16
|
215 template< typename CharT >
|
Chris@16
|
216 struct c_ascii_decorator_gen
|
Chris@16
|
217 {
|
Chris@16
|
218 typedef CharT char_type;
|
Chris@16
|
219
|
Chris@16
|
220 template< typename SubactorT >
|
Chris@16
|
221 BOOST_FORCEINLINE char_decorator_actor< SubactorT, c_ascii_pattern_replacer< char_type > > operator[] (SubactorT const& subactor) const
|
Chris@16
|
222 {
|
Chris@16
|
223 typedef c_decorator_traits< char_type > traits_type;
|
Chris@16
|
224 typedef c_ascii_pattern_replacer< char_type > replacer_type;
|
Chris@16
|
225 typedef char_decorator_actor< SubactorT, replacer_type > result_type;
|
Chris@16
|
226 typedef typename result_type::terminal_type terminal_type;
|
Chris@16
|
227 typename result_type::base_type act = {{ terminal_type(subactor, replacer_type()) }};
|
Chris@16
|
228 return result_type(act);
|
Chris@16
|
229 }
|
Chris@16
|
230 };
|
Chris@16
|
231
|
Chris@16
|
232 } // namespace aux
|
Chris@16
|
233
|
Chris@16
|
234 /*!
|
Chris@16
|
235 * C-style decorator generator object. Acts similarly to \c c_decor, except that \c c_ascii_decor also
|
Chris@16
|
236 * converts all non-ASCII and non-printable ASCII characters, except for space character, into
|
Chris@16
|
237 * C-style hexadecimal escape sequences. The generator provides <tt>operator[]</tt> that
|
Chris@16
|
238 * can be used to construct the actual decorator. For example:
|
Chris@16
|
239 *
|
Chris@16
|
240 * <code>
|
Chris@16
|
241 * c_ascii_decor[ attr< std::string >("MyAttr") ]
|
Chris@16
|
242 * </code>
|
Chris@16
|
243 *
|
Chris@16
|
244 * For wide-character formatting there is the similar \c wc_ascii_decor decorator generator object.
|
Chris@16
|
245 */
|
Chris@16
|
246 #ifdef BOOST_LOG_USE_CHAR
|
Chris@16
|
247 const aux::c_ascii_decorator_gen< char > c_ascii_decor = {};
|
Chris@16
|
248 #endif
|
Chris@16
|
249 #ifdef BOOST_LOG_USE_WCHAR_T
|
Chris@16
|
250 const aux::c_ascii_decorator_gen< wchar_t > wc_ascii_decor = {};
|
Chris@16
|
251 #endif
|
Chris@16
|
252
|
Chris@16
|
253 /*!
|
Chris@16
|
254 * The function creates a C-style decorator generator for arbitrary character type.
|
Chris@16
|
255 */
|
Chris@16
|
256 template< typename CharT >
|
Chris@16
|
257 BOOST_FORCEINLINE aux::c_ascii_decorator_gen< CharT > make_c_ascii_decor()
|
Chris@16
|
258 {
|
Chris@16
|
259 return aux::c_ascii_decorator_gen< CharT >();
|
Chris@16
|
260 }
|
Chris@16
|
261
|
Chris@16
|
262 } // namespace expressions
|
Chris@16
|
263
|
Chris@16
|
264 BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
Chris@16
|
265
|
Chris@16
|
266 } // namespace boost
|
Chris@16
|
267
|
Chris@16
|
268 #include <boost/log/detail/footer.hpp>
|
Chris@16
|
269
|
Chris@16
|
270 #endif // BOOST_LOG_EXPRESSIONS_FORMATTERS_C_DECORATOR_HPP_INCLUDED_
|