1 2 #ifndef DATE_TIME_DATE_GENERATOR_PARSER_HPP__ 3 #define DATE_TIME_DATE_GENERATOR_PARSER_HPP__ 4 5 /* Copyright (c) 2005 CrystalClear Software, Inc. 6 * Use, modification and distribution is subject to the 7 * Boost Software License, Version 1.0. (See accompanying 8 * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) 9 * Author: Jeff Garland, Bart Garst 10 * $Date$ 11 */ 12 13 #include <string> 14 #include <vector> 15 #include <iterator> // istreambuf_iterator 16 #include <boost/throw_exception.hpp> 17 #include <boost/date_time/compiler_config.hpp> 18 #include <boost/date_time/string_parse_tree.hpp> 19 #include <boost/date_time/date_generators.hpp> 20 #include <boost/date_time/format_date_parser.hpp> 21 22 namespace boost { namespace date_time { 23 24 //! Class for date_generator parsing 25 /*! The elements of a date_generator "phrase" are parsed from the input stream in a 26 * particular order. All elements are required and the order in which they appear 27 * cannot change, however, the elements themselves can be changed. The default 28 * elements and their order are as follows: 29 * 30 * - partial_date => "dd Month" 31 * - nth_day_of_the_week_in_month => "nth weekday of month" 32 * - first_day_of_the_week_in_month => "first weekday of month" 33 * - last_day_of_the_week_in_month => "last weekday of month" 34 * - first_day_of_the_week_after => "weekday after" 35 * - first_day_of_the_week_before => "weekday before" 36 * 37 * Weekday and Month names and formats are handled via the date_input_facet. 38 * 39 */ 40 template<class date_type, typename charT> 41 class date_generator_parser 42 { 43 public: 44 typedef std::basic_string<charT> string_type; 45 typedef std::istreambuf_iterator<charT> stream_itr_type; 46 47 typedef typename date_type::month_type month_type; 48 typedef typename date_type::day_of_week_type day_of_week_type; 49 typedef typename date_type::day_type day_type; 50 51 typedef string_parse_tree<charT> parse_tree_type; 52 typedef typename parse_tree_type::parse_match_result_type match_results; 53 typedef std::vector<std::basic_string<charT> > collection_type; 54 55 typedef partial_date<date_type> partial_date_type; 56 typedef nth_kday_of_month<date_type> nth_kday_type; 57 typedef first_kday_of_month<date_type> first_kday_type; 58 typedef last_kday_of_month<date_type> last_kday_type; 59 typedef first_kday_after<date_type> kday_after_type; 60 typedef first_kday_before<date_type> kday_before_type; 61 62 typedef charT char_type; 63 static const char_type first_string[6]; 64 static const char_type second_string[7]; 65 static const char_type third_string[6]; 66 static const char_type fourth_string[7]; 67 static const char_type fifth_string[6]; 68 static const char_type last_string[5]; 69 static const char_type before_string[8]; 70 static const char_type after_string[6]; 71 static const char_type of_string[3]; 72 73 enum phrase_elements {first=0, second, third, fourth, fifth, last, 74 before, after, of, number_of_phrase_elements}; 75 76 //! Creates a date_generator_parser with the default set of "element_strings" date_generator_parser()77 date_generator_parser() 78 { 79 element_strings(string_type(first_string), 80 string_type(second_string), 81 string_type(third_string), 82 string_type(fourth_string), 83 string_type(fifth_string), 84 string_type(last_string), 85 string_type(before_string), 86 string_type(after_string), 87 string_type(of_string)); 88 } 89 90 //! Creates a date_generator_parser using a user defined set of element strings date_generator_parser(const string_type & first_str,const string_type & second_str,const string_type & third_str,const string_type & fourth_str,const string_type & fifth_str,const string_type & last_str,const string_type & before_str,const string_type & after_str,const string_type & of_str)91 date_generator_parser(const string_type& first_str, 92 const string_type& second_str, 93 const string_type& third_str, 94 const string_type& fourth_str, 95 const string_type& fifth_str, 96 const string_type& last_str, 97 const string_type& before_str, 98 const string_type& after_str, 99 const string_type& of_str) 100 { 101 element_strings(first_str, second_str, third_str, fourth_str, fifth_str, 102 last_str, before_str, after_str, of_str); 103 } 104 105 //! Replace strings that determine nth week for generator element_strings(const string_type & first_str,const string_type & second_str,const string_type & third_str,const string_type & fourth_str,const string_type & fifth_str,const string_type & last_str,const string_type & before_str,const string_type & after_str,const string_type & of_str)106 void element_strings(const string_type& first_str, 107 const string_type& second_str, 108 const string_type& third_str, 109 const string_type& fourth_str, 110 const string_type& fifth_str, 111 const string_type& last_str, 112 const string_type& before_str, 113 const string_type& after_str, 114 const string_type& of_str) 115 { 116 collection_type phrases; 117 phrases.push_back(first_str); 118 phrases.push_back(second_str); 119 phrases.push_back(third_str); 120 phrases.push_back(fourth_str); 121 phrases.push_back(fifth_str); 122 phrases.push_back(last_str); 123 phrases.push_back(before_str); 124 phrases.push_back(after_str); 125 phrases.push_back(of_str); 126 m_element_strings = parse_tree_type(phrases, this->first); // enum first 127 } 128 element_strings(const collection_type & col)129 void element_strings(const collection_type& col) 130 { 131 m_element_strings = parse_tree_type(col, this->first); // enum first 132 } 133 134 //! returns partial_date parsed from stream 135 template<class facet_type> 136 partial_date_type get_partial_date_type(stream_itr_type & sitr,stream_itr_type & stream_end,std::ios_base & a_ios,const facet_type & facet) const137 get_partial_date_type(stream_itr_type& sitr, 138 stream_itr_type& stream_end, 139 std::ios_base& a_ios, 140 const facet_type& facet) const 141 { 142 // skip leading whitespace 143 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 144 145 day_type d(1); 146 month_type m(1); 147 facet.get(sitr, stream_end, a_ios, d); 148 facet.get(sitr, stream_end, a_ios, m); 149 150 return partial_date_type(d,m); 151 } 152 153 //! returns nth_kday_of_week parsed from stream 154 template<class facet_type> 155 nth_kday_type get_nth_kday_type(stream_itr_type & sitr,stream_itr_type & stream_end,std::ios_base & a_ios,const facet_type & facet) const156 get_nth_kday_type(stream_itr_type& sitr, 157 stream_itr_type& stream_end, 158 std::ios_base& a_ios, 159 const facet_type& facet) const 160 { 161 // skip leading whitespace 162 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 163 164 typename nth_kday_type::week_num wn; 165 day_of_week_type wd(0); // no default constructor 166 month_type m(1); // no default constructor 167 168 match_results mr = m_element_strings.match(sitr, stream_end); 169 switch(mr.current_match) { 170 case first : { wn = nth_kday_type::first; break; } 171 case second : { wn = nth_kday_type::second; break; } 172 case third : { wn = nth_kday_type::third; break; } 173 case fourth : { wn = nth_kday_type::fourth; break; } 174 case fifth : { wn = nth_kday_type::fifth; break; } 175 default: 176 { 177 boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'")); 178 BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(wn = nth_kday_type::first); 179 } 180 } // week num 181 facet.get(sitr, stream_end, a_ios, wd); // day_of_week 182 extract_element(sitr, stream_end, of); // "of" element 183 facet.get(sitr, stream_end, a_ios, m); // month 184 185 return nth_kday_type(wn, wd, m); 186 } 187 188 //! returns first_kday_of_week parsed from stream 189 template<class facet_type> 190 first_kday_type get_first_kday_type(stream_itr_type & sitr,stream_itr_type & stream_end,std::ios_base & a_ios,const facet_type & facet) const191 get_first_kday_type(stream_itr_type& sitr, 192 stream_itr_type& stream_end, 193 std::ios_base& a_ios, 194 const facet_type& facet) const 195 { 196 // skip leading whitespace 197 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 198 199 day_of_week_type wd(0); // no default constructor 200 month_type m(1); // no default constructor 201 202 extract_element(sitr, stream_end, first); // "first" element 203 facet.get(sitr, stream_end, a_ios, wd); // day_of_week 204 extract_element(sitr, stream_end, of); // "of" element 205 facet.get(sitr, stream_end, a_ios, m); // month 206 207 208 return first_kday_type(wd, m); 209 } 210 211 //! returns last_kday_of_week parsed from stream 212 template<class facet_type> 213 last_kday_type get_last_kday_type(stream_itr_type & sitr,stream_itr_type & stream_end,std::ios_base & a_ios,const facet_type & facet) const214 get_last_kday_type(stream_itr_type& sitr, 215 stream_itr_type& stream_end, 216 std::ios_base& a_ios, 217 const facet_type& facet) const 218 { 219 // skip leading whitespace 220 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 221 222 day_of_week_type wd(0); // no default constructor 223 month_type m(1); // no default constructor 224 225 extract_element(sitr, stream_end, last); // "last" element 226 facet.get(sitr, stream_end, a_ios, wd); // day_of_week 227 extract_element(sitr, stream_end, of); // "of" element 228 facet.get(sitr, stream_end, a_ios, m); // month 229 230 231 return last_kday_type(wd, m); 232 } 233 234 //! returns first_kday_of_week parsed from stream 235 template<class facet_type> 236 kday_before_type get_kday_before_type(stream_itr_type & sitr,stream_itr_type & stream_end,std::ios_base & a_ios,const facet_type & facet) const237 get_kday_before_type(stream_itr_type& sitr, 238 stream_itr_type& stream_end, 239 std::ios_base& a_ios, 240 const facet_type& facet) const 241 { 242 // skip leading whitespace 243 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 244 245 day_of_week_type wd(0); // no default constructor 246 247 facet.get(sitr, stream_end, a_ios, wd); // day_of_week 248 extract_element(sitr, stream_end, before);// "before" element 249 250 return kday_before_type(wd); 251 } 252 253 //! returns first_kday_of_week parsed from stream 254 template<class facet_type> 255 kday_after_type get_kday_after_type(stream_itr_type & sitr,stream_itr_type & stream_end,std::ios_base & a_ios,const facet_type & facet) const256 get_kday_after_type(stream_itr_type& sitr, 257 stream_itr_type& stream_end, 258 std::ios_base& a_ios, 259 const facet_type& facet) const 260 { 261 // skip leading whitespace 262 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 263 264 day_of_week_type wd(0); // no default constructor 265 266 facet.get(sitr, stream_end, a_ios, wd); // day_of_week 267 extract_element(sitr, stream_end, after); // "after" element 268 269 return kday_after_type(wd); 270 } 271 272 private: 273 parse_tree_type m_element_strings; 274 275 //! Extracts phrase element from input. Throws ios_base::failure on error. extract_element(stream_itr_type & sitr,stream_itr_type & stream_end,typename date_generator_parser::phrase_elements ele) const276 void extract_element(stream_itr_type& sitr, 277 stream_itr_type& stream_end, 278 typename date_generator_parser::phrase_elements ele) const 279 { 280 // skip leading whitespace 281 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 282 match_results mr = m_element_strings.match(sitr, stream_end); 283 if(mr.current_match != ele) { 284 boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'")); 285 } 286 } 287 288 }; 289 290 template<class date_type, class CharT> 291 const typename date_generator_parser<date_type, CharT>::char_type 292 date_generator_parser<date_type, CharT>::first_string[6] = 293 {'f','i','r','s','t'}; 294 template<class date_type, class CharT> 295 const typename date_generator_parser<date_type, CharT>::char_type 296 date_generator_parser<date_type, CharT>::second_string[7] = 297 {'s','e','c','o','n','d'}; 298 template<class date_type, class CharT> 299 const typename date_generator_parser<date_type, CharT>::char_type 300 date_generator_parser<date_type, CharT>::third_string[6] = 301 {'t','h','i','r','d'}; 302 template<class date_type, class CharT> 303 const typename date_generator_parser<date_type, CharT>::char_type 304 date_generator_parser<date_type, CharT>::fourth_string[7] = 305 {'f','o','u','r','t','h'}; 306 template<class date_type, class CharT> 307 const typename date_generator_parser<date_type, CharT>::char_type 308 date_generator_parser<date_type, CharT>::fifth_string[6] = 309 {'f','i','f','t','h'}; 310 template<class date_type, class CharT> 311 const typename date_generator_parser<date_type, CharT>::char_type 312 date_generator_parser<date_type, CharT>::last_string[5] = 313 {'l','a','s','t'}; 314 template<class date_type, class CharT> 315 const typename date_generator_parser<date_type, CharT>::char_type 316 date_generator_parser<date_type, CharT>::before_string[8] = 317 {'b','e','f','o','r','e'}; 318 template<class date_type, class CharT> 319 const typename date_generator_parser<date_type, CharT>::char_type 320 date_generator_parser<date_type, CharT>::after_string[6] = 321 {'a','f','t','e','r'}; 322 template<class date_type, class CharT> 323 const typename date_generator_parser<date_type, CharT>::char_type 324 date_generator_parser<date_type, CharT>::of_string[3] = 325 {'o','f'}; 326 327 } } //namespace 328 329 #endif // DATE_TIME_DATE_GENERATOR_PARSER_HPP__ 330 331