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
27namespace karma = boost::spirit::karma;
28
29namespace boost {
30
31BOOST_LOG_OPEN_NAMESPACE
32
33namespace aux {
34
35BOOST_LOG_ANONYMOUS_NAMESPACE {
36
37template< typename CharT >
38struct string_constants;
39
40#ifdef BOOST_LOG_USE_CHAR
41
42template< >
43struct 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
59template< >
60struct 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
74template< typename CallbackT >
75struct 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
113private:
114 string_type m_literal;
115};
116
117template< typename BaseT >
118struct 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(s1: begin, s2: constants::extended_iso_date_format(), n: 8 * sizeof(char_type)) == 0)
136 {
137 callback.on_extended_iso_date();
138 return begin + 8;
139 }
140 else if (len >= 6 && std::memcmp(s1: begin, s2: constants::iso_date_format(), n: 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
205template< typename BaseT >
206struct 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(s1: begin, s2: constants::default_time_format(), n: 11 * sizeof(char_type)) == 0)
225 {
226 callback.on_default_time();
227 return begin + 11;
228 }
229 else if (len >= 8 && std::memcmp(s1: begin, s2: constants::extended_iso_time_format(), n: 8 * sizeof(char_type)) == 0)
230 {
231 callback.on_extended_iso_time();
232 return begin + 8;
233 }
234 else if (len >= 6 && std::memcmp(s1: begin, s2: constants::iso_time_format(), n: 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
319template< typename CharT, typename ParserT, typename CallbackT >
320inline 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
347template< typename CharT >
348BOOST_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
357template< typename CharT >
358BOOST_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
367template< typename CharT >
368BOOST_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
376template< typename CharT >
377BOOST_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
393template BOOST_LOG_API
394void parse_date_format(const char* begin, const char* end, date_format_parser_callback< char >& callback);
395template BOOST_LOG_API
396void parse_time_format(const char* begin, const char* end, time_format_parser_callback< char >& callback);
397template BOOST_LOG_API
398void parse_date_time_format(const char* begin, const char* end, date_time_format_parser_callback< char >& callback);
399template BOOST_LOG_API
400void 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
406template BOOST_LOG_API
407void parse_date_format(const wchar_t* begin, const wchar_t* end, date_format_parser_callback< wchar_t >& callback);
408template BOOST_LOG_API
409void parse_time_format(const wchar_t* begin, const wchar_t* end, time_format_parser_callback< wchar_t >& callback);
410template BOOST_LOG_API
411void parse_date_time_format(const wchar_t* begin, const wchar_t* end, date_time_format_parser_callback< wchar_t >& callback);
412template BOOST_LOG_API
413void 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
419BOOST_LOG_CLOSE_NAMESPACE // namespace log
420
421} // namespace boost
422
423#include <boost/log/detail/footer.hpp>
424

source code of boost/libs/log/src/date_time_format_parser.cpp