date_time_format_parser.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  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.hpp
  9. * \author Andrey Semashev
  10. * \date 16.09.2012
  11. *
  12. * The header contains a parser for date and time format strings.
  13. */
  14. #ifndef BOOST_LOG_DETAIL_DATE_TIME_FORMAT_PARSER_HPP_INCLUDED_
  15. #define BOOST_LOG_DETAIL_DATE_TIME_FORMAT_PARSER_HPP_INCLUDED_
  16. #include <string>
  17. #include <boost/range/as_literal.hpp>
  18. #include <boost/range/iterator_range_core.hpp>
  19. #include <boost/log/detail/config.hpp>
  20. #include <boost/log/detail/header.hpp>
  21. #ifdef BOOST_HAS_PRAGMA_ONCE
  22. #pragma once
  23. #endif
  24. namespace boost {
  25. BOOST_LOG_OPEN_NAMESPACE
  26. namespace aux {
  27. /*!
  28. * This is the interface the parser will use to notify the caller about various components of date in the format string.
  29. */
  30. template< typename CharT >
  31. struct date_format_parser_callback
  32. {
  33. //! Character type used by the parser
  34. typedef CharT char_type;
  35. //! Destructor
  36. virtual ~date_format_parser_callback() {}
  37. /*!
  38. * \brief The function is called when the parser discovers a string literal in the format string
  39. *
  40. * \param lit The string of characters not interpreted as a placeholder
  41. */
  42. virtual void on_literal(iterator_range< const char_type* > const& lit) = 0;
  43. /*!
  44. * \brief The method is called when an unknown placeholder is found in the format string
  45. *
  46. * \param ph The placeholder with the leading percent sign
  47. */
  48. virtual void on_placeholder(iterator_range< const char_type* > const& ph)
  49. {
  50. // By default interpret all unrecognized placeholders as literals
  51. on_literal(ph);
  52. }
  53. /*!
  54. * \brief The function is called when the short year placeholder is found in the format string
  55. */
  56. virtual void on_short_year()
  57. {
  58. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('y'), static_cast< char_type >('\0') };
  59. on_placeholder(boost::as_literal(placeholder));
  60. }
  61. /*!
  62. * \brief The function is called when the full year placeholder is found in the format string
  63. */
  64. virtual void on_full_year()
  65. {
  66. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('Y'), static_cast< char_type >('\0') };
  67. on_placeholder(boost::as_literal(placeholder));
  68. }
  69. /*!
  70. * \brief The function is called when the numeric month placeholder is found in the format string
  71. */
  72. virtual void on_numeric_month()
  73. {
  74. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('m'), static_cast< char_type >('\0') };
  75. on_placeholder(boost::as_literal(placeholder));
  76. }
  77. /*!
  78. * \brief The function is called when the short alphabetic month placeholder is found in the format string
  79. */
  80. virtual void on_short_month()
  81. {
  82. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('b'), static_cast< char_type >('\0') };
  83. on_placeholder(boost::as_literal(placeholder));
  84. }
  85. /*!
  86. * \brief The function is called when the full alphabetic month placeholder is found in the format string
  87. */
  88. virtual void on_full_month()
  89. {
  90. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('B'), static_cast< char_type >('\0') };
  91. on_placeholder(boost::as_literal(placeholder));
  92. }
  93. /*!
  94. * \brief The function is called when the numeric day of month placeholder is found in the format string
  95. *
  96. * \param leading_zero If \c true, the day should be formatted with leading zero, otherwise with leading space
  97. */
  98. virtual void on_month_day(bool leading_zero)
  99. {
  100. const char_type placeholder[3] = { static_cast< char_type >('%'), (leading_zero ? static_cast< char_type >('d') : static_cast< char_type >('e')), static_cast< char_type >('\0') };
  101. on_placeholder(boost::as_literal(placeholder));
  102. }
  103. /*!
  104. * \brief The function is called when the numeric day of week placeholder is found in the format string
  105. */
  106. virtual void on_numeric_week_day()
  107. {
  108. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('w'), static_cast< char_type >('\0') };
  109. on_placeholder(boost::as_literal(placeholder));
  110. }
  111. /*!
  112. * \brief The function is called when the short alphabetic day of week placeholder is found in the format string
  113. */
  114. virtual void on_short_week_day()
  115. {
  116. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('a'), static_cast< char_type >('\0') };
  117. on_placeholder(boost::as_literal(placeholder));
  118. }
  119. /*!
  120. * \brief The function is called when the full alphabetic day of week placeholder is found in the format string
  121. */
  122. virtual void on_full_week_day()
  123. {
  124. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('A'), static_cast< char_type >('\0') };
  125. on_placeholder(boost::as_literal(placeholder));
  126. }
  127. /*!
  128. * \brief The function is called when the ISO-formatted date is found in the format string
  129. */
  130. virtual void on_iso_date()
  131. {
  132. on_full_year();
  133. on_numeric_month();
  134. on_month_day(true);
  135. }
  136. /*!
  137. * \brief The function is called when the extended ISO-formatted date is found in the format string
  138. */
  139. virtual void on_extended_iso_date()
  140. {
  141. const char_type delimiter[2] = { static_cast< char_type >('-'), static_cast< char_type >('\0') };
  142. on_full_year();
  143. on_literal(boost::as_literal(delimiter));
  144. on_numeric_month();
  145. on_literal(boost::as_literal(delimiter));
  146. on_month_day(true);
  147. }
  148. };
  149. /*!
  150. * This is the interface the parser will use to notify the caller about various components of date in the format string.
  151. */
  152. template< typename CharT >
  153. struct time_format_parser_callback
  154. {
  155. //! Character type used by the parser
  156. typedef CharT char_type;
  157. //! Destructor
  158. virtual ~time_format_parser_callback() {}
  159. /*!
  160. * \brief The function is called when the parser discovers a string literal in the format string
  161. *
  162. * \param lit The string of characters not interpreted as a placeholder
  163. */
  164. virtual void on_literal(iterator_range< const char_type* > const& lit) = 0;
  165. /*!
  166. * \brief The method is called when an unknown placeholder is found in the format string
  167. *
  168. * \param ph The placeholder with the leading percent sign
  169. */
  170. virtual void on_placeholder(iterator_range< const char_type* > const& ph)
  171. {
  172. // By default interpret all unrecognized placeholders as literals
  173. on_literal(ph);
  174. }
  175. /*!
  176. * \brief The function is called when the hours placeholder is found in the format string
  177. *
  178. * The placeholder is used for 24-hour clock and duration formatting.
  179. *
  180. * \param leading_zero If \c true, the one-digit number of hours should be formatted with leading zero, otherwise with leading space
  181. */
  182. virtual void on_hours(bool leading_zero)
  183. {
  184. const char_type placeholder[3] = { static_cast< char_type >('%'), (leading_zero ? static_cast< char_type >('O') : static_cast< char_type >('k')), static_cast< char_type >('\0') };
  185. on_placeholder(boost::as_literal(placeholder));
  186. }
  187. /*!
  188. * \brief The function is called when the hours placeholder is found in the format string
  189. *
  190. * The placeholder is used for 12-hour clock formatting. It should not be used for duration formatting.
  191. *
  192. * \param leading_zero If \c true, the one-digit number of hours should be formatted with leading zero, otherwise with leading space
  193. */
  194. virtual void on_hours_12(bool leading_zero)
  195. {
  196. const char_type placeholder[3] = { static_cast< char_type >('%'), (leading_zero ? static_cast< char_type >('I') : static_cast< char_type >('l')), static_cast< char_type >('\0') };
  197. on_placeholder(boost::as_literal(placeholder));
  198. }
  199. /*!
  200. * \brief The function is called when the minutes placeholder is found in the format string
  201. */
  202. virtual void on_minutes()
  203. {
  204. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('M'), static_cast< char_type >('\0') };
  205. on_placeholder(boost::as_literal(placeholder));
  206. }
  207. /*!
  208. * \brief The function is called when the seconds placeholder is found in the format string
  209. */
  210. virtual void on_seconds()
  211. {
  212. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('S'), static_cast< char_type >('\0') };
  213. on_placeholder(boost::as_literal(placeholder));
  214. }
  215. /*!
  216. * \brief The function is called when the fractional seconds placeholder is found in the format string
  217. */
  218. virtual void on_fractional_seconds()
  219. {
  220. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('f'), static_cast< char_type >('\0') };
  221. on_placeholder(boost::as_literal(placeholder));
  222. }
  223. /*!
  224. * \brief The function is called when the day period (AM/PM) placeholder is found in the format string
  225. *
  226. * The placeholder is used for 12-hour clock formatting. It should not be used for duration formatting.
  227. *
  228. * \param upper_case If \c true, the day period will be upper case, and lower case otherwise
  229. */
  230. virtual void on_am_pm(bool upper_case)
  231. {
  232. const char_type placeholder[3] = { static_cast< char_type >('%'), (upper_case ? static_cast< char_type >('p') : static_cast< char_type >('P')), static_cast< char_type >('\0') };
  233. on_placeholder(boost::as_literal(placeholder));
  234. }
  235. /*!
  236. * \brief The function is called when the time duration sign placeholder is found in the format string
  237. *
  238. * The placeholder is used for duration formatting. It should not be used for time point formatting.
  239. *
  240. * \param display_positive If \c true, the positive sign will be explicitly displayed, otherwise only negative sign will be displayed
  241. */
  242. virtual void on_duration_sign(bool display_positive)
  243. {
  244. const char_type placeholder[3] = { static_cast< char_type >('%'), (display_positive ? static_cast< char_type >('+') : static_cast< char_type >('-')), static_cast< char_type >('\0') };
  245. on_placeholder(boost::as_literal(placeholder));
  246. }
  247. /*!
  248. * \brief The function is called when the ISO time zone placeholder is found in the format string
  249. */
  250. virtual void on_iso_time_zone()
  251. {
  252. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('q'), static_cast< char_type >('\0') };
  253. on_placeholder(boost::as_literal(placeholder));
  254. }
  255. /*!
  256. * \brief The function is called when the extended ISO time zone placeholder is found in the format string
  257. */
  258. virtual void on_extended_iso_time_zone()
  259. {
  260. const char_type placeholder[3] = { static_cast< char_type >('%'), static_cast< char_type >('Q'), static_cast< char_type >('\0') };
  261. on_placeholder(boost::as_literal(placeholder));
  262. }
  263. /*!
  264. * \brief The function is called when the ISO-formatted time is found in the format string
  265. */
  266. virtual void on_iso_time()
  267. {
  268. on_hours(true);
  269. on_minutes();
  270. on_seconds();
  271. }
  272. /*!
  273. * \brief The function is called when the extended ISO-formatted time is found in the format string
  274. */
  275. virtual void on_extended_iso_time()
  276. {
  277. const char_type delimiter[2] = { static_cast< char_type >(':'), static_cast< char_type >('\0') };
  278. on_hours(true);
  279. on_literal(boost::as_literal(delimiter));
  280. on_minutes();
  281. on_literal(boost::as_literal(delimiter));
  282. on_seconds();
  283. }
  284. /*!
  285. * \brief The function is called when the extended ISO-formatted time with fractional seconds is found in the format string
  286. */
  287. virtual void on_default_time()
  288. {
  289. on_extended_iso_time();
  290. const char_type delimiter[2] = { static_cast< char_type >('.'), static_cast< char_type >('\0') };
  291. on_literal(boost::as_literal(delimiter));
  292. on_fractional_seconds();
  293. }
  294. };
  295. /*!
  296. * This is the interface the parser will use to notify the caller about various components of date in the format string.
  297. */
  298. template< typename CharT >
  299. struct date_time_format_parser_callback :
  300. public date_format_parser_callback< CharT >,
  301. public time_format_parser_callback< CharT >
  302. {
  303. //! Character type used by the parser
  304. typedef CharT char_type;
  305. //! Destructor
  306. virtual ~date_time_format_parser_callback() {}
  307. /*!
  308. * \brief The function is called when the parser discovers a string literal in the format string
  309. *
  310. * \param lit The string of characters not interpreted as a placeholder
  311. */
  312. virtual void on_literal(iterator_range< const char_type* > const& lit) = 0;
  313. /*!
  314. * \brief The method is called when an unknown placeholder is found in the format string
  315. *
  316. * \param ph The placeholder with the leading percent sign
  317. */
  318. virtual void on_placeholder(iterator_range< const char_type* > const& ph)
  319. {
  320. // By default interpret all unrecognized placeholders as literals
  321. on_literal(ph);
  322. }
  323. };
  324. /*!
  325. * \brief Parses the date format string and invokes the callback object
  326. *
  327. * \pre <tt>begin <= end</tt>, both pointers must not be \c NULL
  328. * \param begin Pointer to the first character of the sequence
  329. * \param end Pointer to the after-the-last character of the sequence
  330. * \param callback Reference to the callback object that will be invoked by the parser as it processes the input
  331. */
  332. template< typename CharT >
  333. BOOST_LOG_API void parse_date_format(const CharT* begin, const CharT* end, date_format_parser_callback< CharT >& callback);
  334. /*!
  335. * \brief Parses the date format string and invokes the callback object
  336. *
  337. * \param str The format string to parse
  338. * \param callback Reference to the callback object that will be invoked by the parser as it processes the input
  339. */
  340. template< typename CharT, typename TraitsT, typename AllocatorT >
  341. inline void parse_date_format(std::basic_string< CharT, TraitsT, AllocatorT > const& str, date_format_parser_callback< CharT >& callback)
  342. {
  343. const CharT* p = str.c_str();
  344. return parse_date_format(p, p + str.size(), callback);
  345. }
  346. /*!
  347. * \brief Parses the date format string and invokes the callback object
  348. *
  349. * \pre <tt>str != NULL</tt>, <tt>str</tt> points to a zero-terminated string.
  350. * \param str The format string to parse
  351. * \param callback Reference to the callback object that will be invoked by the parser as it processes the input
  352. */
  353. template< typename CharT >
  354. inline void parse_date_format(const CharT* str, date_format_parser_callback< CharT >& callback)
  355. {
  356. return parse_date_format(str, str + std::char_traits< CharT >::length(str), callback);
  357. }
  358. /*!
  359. * \brief Parses the time format string and invokes the callback object
  360. *
  361. * \pre <tt>begin <= end</tt>, both pointers must not be \c NULL
  362. * \param begin Pointer to the first character of the sequence
  363. * \param end Pointer to the after-the-last character of the sequence
  364. * \param callback Reference to the callback object that will be invoked by the parser as it processes the input
  365. */
  366. template< typename CharT >
  367. BOOST_LOG_API void parse_time_format(const CharT* begin, const CharT* end, time_format_parser_callback< CharT >& callback);
  368. /*!
  369. * \brief Parses the time format string and invokes the callback object
  370. *
  371. * \param str The format string to parse
  372. * \param callback Reference to the callback object that will be invoked by the parser as it processes the input
  373. */
  374. template< typename CharT, typename TraitsT, typename AllocatorT >
  375. inline void parse_time_format(std::basic_string< CharT, TraitsT, AllocatorT > const& str, time_format_parser_callback< CharT >& callback)
  376. {
  377. const CharT* p = str.c_str();
  378. return parse_time_format(p, p + str.size(), callback);
  379. }
  380. /*!
  381. * \brief Parses the time format string and invokes the callback object
  382. *
  383. * \pre <tt>str != NULL</tt>, <tt>str</tt> points to a zero-terminated string.
  384. * \param str The format string to parse
  385. * \param callback Reference to the callback object that will be invoked by the parser as it processes the input
  386. */
  387. template< typename CharT >
  388. inline void parse_time_format(const CharT* str, time_format_parser_callback< CharT >& callback)
  389. {
  390. return parse_time_format(str, str + std::char_traits< CharT >::length(str), callback);
  391. }
  392. /*!
  393. * \brief Parses the date and time format string and invokes the callback object
  394. *
  395. * \pre <tt>begin <= end</tt>, both pointers must not be \c NULL
  396. * \param begin Pointer to the first character of the sequence
  397. * \param end Pointer to the after-the-last character of the sequence
  398. * \param callback Reference to the callback object that will be invoked by the parser as it processes the input
  399. */
  400. template< typename CharT >
  401. BOOST_LOG_API void parse_date_time_format(const CharT* begin, const CharT* end, date_time_format_parser_callback< CharT >& callback);
  402. /*!
  403. * \brief Parses the date and time format string and invokes the callback object
  404. *
  405. * \param str The format string to parse
  406. * \param callback Reference to the callback object that will be invoked by the parser as it processes the input
  407. */
  408. template< typename CharT, typename TraitsT, typename AllocatorT >
  409. inline void parse_date_time_format(std::basic_string< CharT, TraitsT, AllocatorT > const& str, date_time_format_parser_callback< CharT >& callback)
  410. {
  411. const CharT* p = str.c_str();
  412. return parse_date_time_format(p, p + str.size(), callback);
  413. }
  414. /*!
  415. * \brief Parses the date and time format string and invokes the callback object
  416. *
  417. * \pre <tt>str != NULL</tt>, <tt>str</tt> points to a zero-terminated string.
  418. * \param str The format string to parse
  419. * \param callback Reference to the callback object that will be invoked by the parser as it processes the input
  420. */
  421. template< typename CharT >
  422. inline void parse_date_time_format(const CharT* str, date_time_format_parser_callback< CharT >& callback)
  423. {
  424. return parse_date_time_format(str, str + std::char_traits< CharT >::length(str), callback);
  425. }
  426. } // namespace aux
  427. BOOST_LOG_CLOSE_NAMESPACE // namespace log
  428. } // namespace boost
  429. #include <boost/log/detail/footer.hpp>
  430. #endif // BOOST_LOG_DETAIL_DATE_TIME_FORMAT_PARSER_HPP_INCLUDED_