Ugly, not-to-be-pushed sucking in of all of Boost to get windows to work.
[dyninst.git] / external / boost / date_time / date_parsing.hpp
1 #ifndef _DATE_TIME_DATE_PARSING_HPP___
2 #define _DATE_TIME_DATE_PARSING_HPP___
3
4 /* Copyright (c) 2002,2003,2005 CrystalClear Software, Inc.
5  * Use, modification and distribution is subject to the 
6  * Boost Software License, Version 1.0. (See accompanying
7  * file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
8  * Author: Jeff Garland, Bart Garst
9  * $Date: 2005/07/13 03:59:54 $
10  */
11
12 #include "boost/tokenizer.hpp"
13 #include "boost/lexical_cast.hpp"
14 #include "boost/date_time/compiler_config.hpp"
15 #include "boost/date_time/parse_format_base.hpp"
16 #include <string>
17 #include <iterator>
18 #include <algorithm>
19
20 #if defined(BOOST_NO_STD_LOCALE)
21 #include <cctype> // ::tolower(int)
22 #else
23 #include <locale> // std::tolower(char, locale)
24 #endif
25
26 namespace boost {
27 namespace date_time {
28
29   //! A function to replace the std::transform( , , ,tolower) construct
30   /*! This function simply takes a string, and changes all the characters
31    * in that string to lowercase (according to the default system locale).
32    * In the event that a compiler does not support locales, the old 
33    * C style tolower() is used.
34    */
35   inline
36   std::string 
37   convert_to_lower(const std::string& inp) {
38     std::string tmp;
39     unsigned i = 0;
40 #if defined(BOOST_NO_STD_LOCALE)
41     while(i < inp.length()) {
42       tmp += static_cast<char>(std::tolower(inp.at(i++)));
43 #else
44       std::locale loc("");
45       while(i < inp.length()) {
46         // tolower and others were brought in to std for borland >= v564
47         // in compiler_config.hpp
48         std::string::value_type c(inp.at(i++));
49         tmp += std::tolower(c, loc);
50 #endif
51         
52       }
53       return tmp;
54     }
55     
56     //! Helper function for parse_date.
57     /* Used by-value parameter because we change the string and may
58      * want to preserve the original argument */
59     template<class month_type>
60     unsigned short 
61     month_str_to_ushort(std::string s) {
62       if((s.at(0) >= '0') && (s.at(0) <= '9')) {
63         return boost::lexical_cast<unsigned short>(s);
64       } 
65       else {
66         s = convert_to_lower(s);
67         typename month_type::month_map_ptr_type ptr = month_type::get_month_map_ptr();
68         typename month_type::month_map_type::iterator iter = ptr->find(s);
69         if(iter != ptr->end()) { // required for STLport
70           return iter->second;
71         }
72       }
73       return 13; // intentionally out of range - name not found
74     }
75  
76     //! Find index of a string in either of 2 arrays
77     /*! find_match searches both arrays for a match to 's'. Indexing of the 
78      * arrays is from 0 to 'limit'. The index of the match is returned.
79      * Ex. "Jan" returns 0, "Dec" returns 11, "Tue" returns 2.
80      * 'limit' can be sent in with: greg_month::max(), 
81      * greg_weekday::max() or date_time::NumSpecialValues */
82     template<class charT>
83     short find_match(const charT* const* short_names, 
84                      const charT* const* long_names, 
85                      short limit,
86                      const std::basic_string<charT>& s) {
87       for(short i = 0; i <= limit; ++i){
88         if(short_names[i] == s || long_names[i] == s){
89           return i;
90         }
91       }
92       return static_cast<short>(limit + 1); // not-found, return a value out of range
93     }
94     
95     //! Generic function to parse a delimited date (eg: 2002-02-10)
96     /*! Accepted formats are: "2003-02-10" or " 2003-Feb-10" or
97      * "2003-Feburary-10" 
98      * The order in which the Month, Day, & Year appear in the argument 
99      * string can be accomodated by passing in the appropriate ymd_order_spec 
100      */
101     template<class date_type>
102     date_type
103     parse_date(const std::string& s, int order_spec = ymd_order_iso) {
104       std::string spec_str("");
105       if(order_spec == ymd_order_iso) {
106         spec_str = "ymd";
107       } 
108       else if(order_spec == ymd_order_dmy) {
109         spec_str = "dmy";
110       } 
111       else { // (order_spec == ymd_order_us)
112         spec_str = "mdy";
113       }
114       
115       typedef typename date_type::year_type year_type;
116       typedef typename date_type::month_type month_type;
117       unsigned pos = 0;
118       unsigned short year(0), month(0), day(0);
119       
120       typedef boost::tokenizer<boost::char_separator<char>,
121                                std::basic_string<char>::const_iterator,
122                                std::basic_string<char> > tokenizer;
123       typedef boost::tokenizer<boost::char_separator<char>,
124                                std::basic_string<char>::const_iterator,
125                                std::basic_string<char> >::iterator tokenizer_iterator;
126       // may need more delimiters, these work for the regression tests
127       const char sep_char[] = {',','-','.',' ','/','\0'};
128       boost::char_separator<char> sep(sep_char);
129       tokenizer tok(s,sep);
130       for(tokenizer_iterator beg=tok.begin(); 
131           beg!=tok.end() && pos < spec_str.size(); 
132           ++beg, ++pos) {
133         switch(spec_str.at(pos)) {
134           case 'y': 
135           {
136             year = boost::lexical_cast<unsigned short>(*beg);
137             break;
138           }
139           case 'm': 
140           {
141             month = month_str_to_ushort<month_type>(*beg);
142             break;
143           }
144           case 'd': 
145           {
146             day = boost::lexical_cast<unsigned short>(*beg);
147             break;
148           }
149         } //switch
150       }
151       return date_type(year, month, day);
152     }
153     
154     //! Generic function to parse undelimited date (eg: 20020201)
155     template<class date_type>
156     date_type
157     parse_undelimited_date(const std::string& s) {
158       int offsets[] = {4,2,2};
159       int pos = 0;
160       typedef typename date_type::year_type year_type;
161       typename date_type::ymd_type ymd((year_type::min)(),1,1);
162       boost::offset_separator osf(offsets, offsets+3);
163       boost::tokenizer<boost::offset_separator> tok(s, osf);
164       for(boost::tokenizer<boost::offset_separator>::iterator ti=tok.begin(); ti!=tok.end();++ti) {
165         unsigned short i = boost::lexical_cast<unsigned short>(*ti);
166         switch(pos) {
167         case 0: ymd.year = i; break;
168         case 1: ymd.month = i; break;
169         case 2: ymd.day = i; break;
170         }
171         pos++;
172       }
173       return date_type(ymd);
174     }
175     
176     //! Helper function for 'date gregorian::from_stream()'
177     /*! Creates a string from the iterators that reference the
178      * begining & end of a char[] or string. All elements are 
179      * used in output string */
180     template<class date_type, class iterator_type>
181     inline 
182     date_type
183     from_stream_type(iterator_type& beg, 
184                      iterator_type& end,
185                      char) 
186     {
187       std::stringstream ss("");
188       while(beg != end) {
189         ss << *beg++;
190       }
191       return parse_date<date_type>(ss.str());
192     }
193  
194     //! Helper function for 'date gregorian::from_stream()'
195     /*! Returns the first string found in the stream referenced by the
196      * begining & end iterators */
197     template<class date_type, class iterator_type>
198     inline 
199     date_type
200     from_stream_type(iterator_type& beg, 
201                      iterator_type& end,
202                      std::string) 
203     {
204       return parse_date<date_type>(*beg);
205     }
206
207     /* I believe the wchar stuff would be best elsewhere, perhaps in
208      * parse_date<>()? In the mean time this gets us started... */
209     //! Helper function for 'date gregorian::from_stream()'
210     /*! Creates a string from the iterators that reference the
211      * begining & end of a wstring. All elements are 
212      * used in output string */
213     template<class date_type, class iterator_type>
214     inline 
215     date_type from_stream_type(iterator_type& beg, 
216                                iterator_type& end,
217                                wchar_t) 
218     {
219       std::stringstream ss("");
220       while(beg != end) {
221 #if !defined(BOOST_DATE_TIME_NO_LOCALE)
222         ss << std::use_facet<std::ctype<wchar_t> >(std::locale()).narrow(*beg++, 'X'); // 'X' will cause exception to be thrown
223 #else
224         ss << ss.narrow(*beg++, 'X');
225 #endif
226       }
227       return parse_date<date_type>(ss.str());
228     }
229 #ifndef BOOST_NO_STD_WSTRING
230     //! Helper function for 'date gregorian::from_stream()'
231     /*! Creates a string from the first wstring found in the stream
232      * referenced by the begining & end iterators */
233     template<class date_type, class iterator_type>
234     inline 
235     date_type
236     from_stream_type(iterator_type& beg, 
237                      iterator_type& end,
238                      std::wstring) {
239       std::wstring ws = *beg;
240       std::stringstream ss("");
241       std::wstring::iterator wsb = ws.begin(), wse = ws.end();
242       while(wsb != wse) {
243 #if !defined(BOOST_DATE_TIME_NO_LOCALE)
244         ss << std::use_facet<std::ctype<wchar_t> >(std::locale()).narrow(*wsb++, 'X'); // 'X' will cause exception to be thrown
245 #else
246         ss << ss.narrow(*wsb++, 'X'); // 'X' will cause exception to be thrown
247 #endif
248       }
249       return parse_date<date_type>(ss.str());
250     }
251 #endif // BOOST_NO_STD_WSTRING
252 #if (defined(BOOST_MSVC) && (_MSC_VER <= 1200))
253     // This function cannot be compiled with MSVC 6.0 due to internal compiler shorcomings
254 #else
255     //! function called by wrapper functions: date_period_from_(w)string()
256     template<class date_type, class charT>
257     period<date_type, typename date_type::duration_type> 
258     from_simple_string_type(const std::basic_string<charT>& s){
259       typedef typename boost::char_separator<charT> char_separator;
260       typedef typename boost::tokenizer<char_separator, typename std::basic_string<charT>::const_iterator, 
261                                           std::basic_string<charT> > tokenizer;
262       const charT sep_list[4] = {'[','/',']','\0'};
263       char_separator sep(sep_list);
264       tokenizer tokens(s, sep);
265       typename tokenizer::iterator tok_it = tokens.begin(); 
266       std::basic_string<charT> date_string = *tok_it;
267       // get 2 string iterators and generate a date from them
268       typename std::basic_string<charT>::iterator date_string_start = date_string.begin(), 
269                                                   date_string_end = date_string.end(); 
270       typedef typename std::iterator_traits<typename std::basic_string<charT>::iterator>::value_type value_type;
271       date_type d1 = from_stream_type<date_type>(date_string_start, date_string_end, value_type());
272       date_string = *(++tok_it); // next token
273       date_string_start = date_string.begin(), date_string_end = date_string.end(); 
274       date_type d2 = from_stream_type<date_type>(date_string_start, date_string_end, value_type());
275       return period<date_type, typename date_type::duration_type>(d1, d2); 
276     }
277 #endif // _MSC_VER <= 1200
278     
279 } } //namespace date_time
280
281
282
283
284 #endif
285