Line data Source code
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"
77 28 : date_generator_parser()
78 14 : {
79 28 : element_strings(string_type(first_string),
80 14 : string_type(second_string),
81 14 : string_type(third_string),
82 14 : string_type(fourth_string),
83 14 : string_type(fifth_string),
84 14 : string_type(last_string),
85 14 : string_type(before_string),
86 14 : string_type(after_string),
87 14 : string_type(of_string));
88 28 : }
89 :
90 : //! Creates a date_generator_parser using a user defined set of element strings
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
106 14 : 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 14 : collection_type phrases;
117 14 : phrases.push_back(first_str);
118 14 : phrases.push_back(second_str);
119 14 : phrases.push_back(third_str);
120 14 : phrases.push_back(fourth_str);
121 14 : phrases.push_back(fifth_str);
122 14 : phrases.push_back(last_str);
123 14 : phrases.push_back(before_str);
124 14 : phrases.push_back(after_str);
125 14 : phrases.push_back(of_str);
126 14 : m_element_strings = parse_tree_type(phrases, this->first); // enum first
127 14 : }
128 :
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
137 : 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
156 : 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
191 : 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
214 : 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
237 : 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
256 : 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.
276 : 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 :
|