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