• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   date_time_format_parser.cpp
9  * \author Andrey Semashev
10  * \date   30.09.2012
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15 
16 #include <boost/log/detail/config.hpp>
17 #include <cstring>
18 #include <string>
19 #include <algorithm>
20 #include <boost/spirit/include/karma_uint.hpp>
21 #include <boost/spirit/include/karma_generate.hpp>
22 #include <boost/range/iterator_range_core.hpp>
23 #include <boost/log/detail/attachable_sstream_buf.hpp>
24 #include <boost/log/detail/date_time_format_parser.hpp>
25 #include <boost/log/detail/header.hpp>
26 
27 namespace karma = boost::spirit::karma;
28 
29 namespace boost {
30 
31 BOOST_LOG_OPEN_NAMESPACE
32 
33 namespace aux {
34 
35 BOOST_LOG_ANONYMOUS_NAMESPACE {
36 
37 template< typename CharT >
38 struct string_constants;
39 
40 #ifdef BOOST_LOG_USE_CHAR
41 
42 template< >
43 struct string_constants< char >
44 {
45     typedef char char_type;
46 
47     static const char_type* iso_date_format() { return "%Y%m%d"; }
48     static const char_type* extended_iso_date_format() { return "%Y-%m-%d"; }
49 
50     static const char_type* iso_time_format() { return "%H%M%S"; }
51     static const char_type* extended_iso_time_format() { return "%H:%M:%S"; }
52     static const char_type* default_time_format() { return "%H:%M:%S.%f"; }
53 };
54 
55 #endif // BOOST_LOG_USE_CHAR
56 
57 #ifdef BOOST_LOG_USE_WCHAR_T
58 
59 template< >
60 struct string_constants< wchar_t >
61 {
62     typedef wchar_t char_type;
63 
64     static const char_type* iso_date_format() { return L"%Y%m%d"; }
65     static const char_type* extended_iso_date_format() { return L"%Y-%m-%d"; }
66 
67     static const char_type* iso_time_format() { return L"%H%M%S"; }
68     static const char_type* extended_iso_time_format() { return L"%H:%M:%S"; }
69     static const char_type* default_time_format() { return L"%H:%M:%S.%f"; }
70 };
71 
72 #endif // BOOST_LOG_USE_WCHAR_T
73 
74 template< typename CallbackT >
75 struct common_flags
76 {
77     typedef CallbackT callback_type;
78     typedef typename callback_type::char_type char_type;
79     typedef std::basic_string< char_type > string_type;
80 
81     const char_type* parse(const char_type* begin, const char_type* end, callback_type& callback)
82     {
83         switch (begin[1])
84         {
85         case '%':
86             m_literal.push_back('%');
87             break;
88 
89         default:
90             flush(callback);
91             callback.on_placeholder(iterator_range< const char_type* >(begin, begin + 2));
92             break;
93         }
94 
95         return begin + 2;
96     }
97 
98     void add_literal(const char_type* begin, const char_type* end)
99     {
100         m_literal.append(begin, end);
101     }
102 
103     void flush(callback_type& callback)
104     {
105         if (!m_literal.empty())
106         {
107             const char_type* p = m_literal.c_str();
108             callback.on_literal(iterator_range< const char_type* >(p, p + m_literal.size()));
109             m_literal.clear();
110         }
111     }
112 
113 private:
114     string_type m_literal;
115 };
116 
117 template< typename BaseT >
118 struct date_flags :
119     public BaseT
120 {
121     typedef typename BaseT::callback_type callback_type;
122     typedef typename BaseT::char_type char_type;
123 
124     const char_type* parse(const char_type* begin, const char_type* end, callback_type& callback)
125     {
126         typedef string_constants< char_type > constants;
127 
128         switch (begin[1])
129         {
130         case 'Y':
131             {
132                 this->flush(callback);
133 
134                 std::size_t len = end - begin;
135                 if (len >= 8 && std::memcmp(begin, constants::extended_iso_date_format(), 8 * sizeof(char_type)) == 0)
136                 {
137                     callback.on_extended_iso_date();
138                     return begin + 8;
139                 }
140                 else if (len >= 6 && std::memcmp(begin, constants::iso_date_format(), 6 * sizeof(char_type)) == 0)
141                 {
142                     callback.on_iso_date();
143                     return begin + 6;
144                 }
145                 else
146                 {
147                     callback.on_full_year();
148                 }
149             }
150             break;
151 
152         case 'y':
153             this->flush(callback);
154             callback.on_short_year();
155             break;
156 
157         case 'm':
158             this->flush(callback);
159             callback.on_numeric_month();
160             break;
161 
162         case 'B':
163             this->flush(callback);
164             callback.on_full_month();
165             break;
166 
167         case 'b':
168             this->flush(callback);
169             callback.on_short_month();
170             break;
171 
172         case 'd':
173             this->flush(callback);
174             callback.on_month_day(true);
175             break;
176 
177         case 'e':
178             this->flush(callback);
179             callback.on_month_day(false);
180             break;
181 
182         case 'w':
183             this->flush(callback);
184             callback.on_numeric_week_day();
185             break;
186 
187         case 'A':
188             this->flush(callback);
189             callback.on_full_week_day();
190             break;
191 
192         case 'a':
193             this->flush(callback);
194             callback.on_short_week_day();
195             break;
196 
197         default:
198             return BaseT::parse(begin, end, callback);
199         }
200 
201         return begin + 2;
202     }
203 };
204 
205 template< typename BaseT >
206 struct time_flags :
207     public BaseT
208 {
209     typedef typename BaseT::callback_type callback_type;
210     typedef typename BaseT::char_type char_type;
211 
212     const char_type* parse(const char_type* begin, const char_type* end, callback_type& callback)
213     {
214         typedef string_constants< char_type > constants;
215 
216         switch (begin[1])
217         {
218         case 'O':
219         case 'H':
220             {
221                 this->flush(callback);
222 
223                 std::size_t len = end - begin;
224                 if (len >= 11 && std::memcmp(begin, constants::default_time_format(), 11 * sizeof(char_type)) == 0)
225                 {
226                     callback.on_default_time();
227                     return begin + 11;
228                 }
229                 else if (len >= 8 && std::memcmp(begin, constants::extended_iso_time_format(), 8 * sizeof(char_type)) == 0)
230                 {
231                     callback.on_extended_iso_time();
232                     return begin + 8;
233                 }
234                 else if (len >= 6 && std::memcmp(begin, constants::iso_time_format(), 6 * sizeof(char_type)) == 0)
235                 {
236                     callback.on_iso_time();
237                     return begin + 6;
238                 }
239                 else
240                 {
241                     callback.on_hours(true);
242                 }
243             }
244             break;
245 
246         case 'T':
247             this->flush(callback);
248             callback.on_extended_iso_time();
249             break;
250 
251         case 'k':
252             this->flush(callback);
253             callback.on_hours(false);
254             break;
255 
256         case 'I':
257             this->flush(callback);
258             callback.on_hours_12(true);
259             break;
260 
261         case 'l':
262             this->flush(callback);
263             callback.on_hours_12(false);
264             break;
265 
266         case 'M':
267             this->flush(callback);
268             callback.on_minutes();
269             break;
270 
271         case 'S':
272             this->flush(callback);
273             callback.on_seconds();
274             break;
275 
276         case 'f':
277             this->flush(callback);
278             callback.on_fractional_seconds();
279             break;
280 
281         case 'P':
282             this->flush(callback);
283             callback.on_am_pm(false);
284             break;
285 
286         case 'p':
287             this->flush(callback);
288             callback.on_am_pm(true);
289             break;
290 
291         case 'Q':
292             this->flush(callback);
293             callback.on_extended_iso_time_zone();
294             break;
295 
296         case 'q':
297             this->flush(callback);
298             callback.on_iso_time_zone();
299             break;
300 
301         case '-':
302             this->flush(callback);
303             callback.on_duration_sign(false);
304             break;
305 
306         case '+':
307             this->flush(callback);
308             callback.on_duration_sign(true);
309             break;
310 
311         default:
312             return BaseT::parse(begin, end, callback);
313         }
314 
315         return begin + 2;
316     }
317 };
318 
319 template< typename CharT, typename ParserT, typename CallbackT >
320 inline void parse_format(const CharT* begin, const CharT* end, ParserT& parser, CallbackT& callback)
321 {
322     typedef CharT char_type;
323 
324     while (begin != end)
325     {
326         const char_type* p = std::find(begin, end, static_cast< char_type >('%'));
327         parser.add_literal(begin, p);
328 
329         if ((end - p) >= 2)
330         {
331             begin = parser.parse(p, end, callback);
332         }
333         else
334         {
335             if (p != end)
336                 parser.add_literal(p, end); // a single '%' character at the end of the string
337             begin = end;
338         }
339     }
340 
341     parser.flush(callback);
342 }
343 
344 } // namespace
345 
346 //! Parses the date format string and invokes the callback object
347 template< typename CharT >
348 BOOST_LOG_API void parse_date_format(const CharT* begin, const CharT* end, date_format_parser_callback< CharT >& callback)
349 {
350     typedef CharT char_type;
351     typedef date_format_parser_callback< char_type > callback_type;
352     date_flags< common_flags< callback_type > > parser;
353     parse_format(begin, end, parser, callback);
354 }
355 
356 //! Parses the time format string and invokes the callback object
357 template< typename CharT >
parse_time_format(const CharT * begin,const CharT * end,time_format_parser_callback<CharT> & callback)358 BOOST_LOG_API void parse_time_format(const CharT* begin, const CharT* end, time_format_parser_callback< CharT >& callback)
359 {
360     typedef CharT char_type;
361     typedef time_format_parser_callback< char_type > callback_type;
362     time_flags< common_flags< callback_type > > parser;
363     parse_format(begin, end, parser, callback);
364 }
365 
366 //! Parses the date and time format string and invokes the callback object
367 template< typename CharT >
parse_date_time_format(const CharT * begin,const CharT * end,date_time_format_parser_callback<CharT> & callback)368 BOOST_LOG_API void parse_date_time_format(const CharT* begin, const CharT* end, date_time_format_parser_callback< CharT >& callback)
369 {
370     typedef CharT char_type;
371     typedef date_time_format_parser_callback< char_type > callback_type;
372     date_flags< time_flags< common_flags< callback_type > > > parser;
373     parse_format(begin, end, parser, callback);
374 }
375 
376 template< typename CharT >
put_integer(boost::log::aux::basic_ostringstreambuf<CharT> & strbuf,uint32_t value,unsigned int width,CharT fill_char)377 BOOST_LOG_API void put_integer(boost::log::aux::basic_ostringstreambuf< CharT >& strbuf, uint32_t value, unsigned int width, CharT fill_char)
378 {
379     typedef CharT char_type;
380     char_type buf[std::numeric_limits< uint32_t >::digits10 + 2];
381     char_type* p = buf;
382 
383     typedef karma::uint_generator< uint32_t, 10 > uint_gen;
384     karma::generate(p, uint_gen(), value);
385     const std::size_t len = p - buf;
386     if (len < width)
387         strbuf.append(width - len, fill_char);
388     strbuf.append(buf, len);
389 }
390 
391 #ifdef BOOST_LOG_USE_CHAR
392 
393 template BOOST_LOG_API
394 void parse_date_format(const char* begin, const char* end, date_format_parser_callback< char >& callback);
395 template BOOST_LOG_API
396 void parse_time_format(const char* begin, const char* end, time_format_parser_callback< char >& callback);
397 template BOOST_LOG_API
398 void parse_date_time_format(const char* begin, const char* end, date_time_format_parser_callback< char >& callback);
399 template BOOST_LOG_API
400 void put_integer(boost::log::aux::basic_ostringstreambuf< char >& strbuf, uint32_t value, unsigned int width, char fill_char);
401 
402 #endif // BOOST_LOG_USE_CHAR
403 
404 #ifdef BOOST_LOG_USE_WCHAR_T
405 
406 template BOOST_LOG_API
407 void parse_date_format(const wchar_t* begin, const wchar_t* end, date_format_parser_callback< wchar_t >& callback);
408 template BOOST_LOG_API
409 void parse_time_format(const wchar_t* begin, const wchar_t* end, time_format_parser_callback< wchar_t >& callback);
410 template BOOST_LOG_API
411 void parse_date_time_format(const wchar_t* begin, const wchar_t* end, date_time_format_parser_callback< wchar_t >& callback);
412 template BOOST_LOG_API
413 void put_integer(boost::log::aux::basic_ostringstreambuf< wchar_t >& strbuf, uint32_t value, unsigned int width, wchar_t fill_char);
414 
415 #endif // BOOST_LOG_USE_WCHAR_T
416 
417 } // namespace aux
418 
419 BOOST_LOG_CLOSE_NAMESPACE // namespace log
420 
421 } // namespace boost
422 
423 #include <boost/log/detail/footer.hpp>
424