1 /*
2  * Copyright (c) 1999
3  * Silicon Graphics Computer Systems, Inc.
4  *
5  * Copyright (c) 1999
6  * Boris Fomitchev
7  *
8  * This material is provided "as is", with absolutely no warranty expressed
9  * or implied. Any use is at your own risk.
10  *
11  * Permission to use or copy this software for any purpose is hereby granted
12  * without fee, provided the above notices are retained on all copies.
13  * Permission to modify the code and to distribute modified code is granted,
14  * provided the above notices are retained, and a notice that the code was
15  * modified is included with the above copyright notice.
16  *
17  */
18 #ifndef _STLP_TIME_FACETS_C
19 #define _STLP_TIME_FACETS_C
20 
21 #ifndef _STLP_INTERNAL_TIME_FACETS_H
22 #  include <stl/_time_facets.h>
23 #endif
24 
25 #ifndef _STLP_INTERNAL_NUM_PUT_H
26 #  include <stl/_num_put.h>
27 #endif
28 
29 #ifndef _STLP_INTERNAL_NUM_GET_H
30 #  include <stl/_num_get.h>
31 #endif
32 
33 _STLP_BEGIN_NAMESPACE
34 
35 //----------------------------------------------------------------------
36 // Declarations of static template members.
37 
38 template <class _CharT, class _InputIterator>
39 locale::id time_get<_CharT, _InputIterator>::id;
40 
41 template <class _CharT, class _OutputIterator>
42 locale::id time_put<_CharT, _OutputIterator>::id;
43 
44 _STLP_MOVE_TO_PRIV_NAMESPACE
45 
46 /* Matching input against a list of names
47 
48  * Alphabetic input of the names of months and the names
49  * of weekdays requires matching input against a list of names.
50  * We use a simple generic algorithm to accomplish this.  This
51  * algorithm is not very efficient, especially for longer lists
52  * of names, but it probably does not matter for the initial
53  * implementation and it may never matter, since we do not expect
54  * this kind of input to be used very often.  The algorithm
55  * could be improved fairly simply by creating a new list of
56  * names still in the running at each iteration.  A more sophisticated
57  * approach would be to build a tree to do the matching.
58  *
59  * We compare each character of the input to the corresponding
60  * character of each name on the list that has not been eliminated,
61  * either because every character in the name has already been
62  * matched, or because some character has not been matched.  We
63  * continue only as long as there are some names that have not been
64  * eliminated.
65 
66  * We do not really need a random access iterator (a forward iterator
67  * would do), but the extra generality makes the notation clumsier,
68  * and we don't really need it.
69 
70  * We can recognize a failed match by the fact that the return value
71  * will be __name_end.
72  */
73 
74 #define _MAXNAMES        24
75 
76 template <class _InIt, class _NameIt>
77 size_t _STLP_CALL
__match(_InIt & __first,_InIt & __last,_NameIt __name,_NameIt __name_end)78 __match(_InIt& __first, _InIt& __last, _NameIt __name, _NameIt __name_end) {
79   typedef ptrdiff_t difference_type;
80   difference_type __n = __name_end - __name;
81   difference_type __i, __start = 0;
82   size_t __pos = 0;
83   difference_type __check_count = __n;
84   bool __do_not_check[_MAXNAMES];
85   size_t __matching_name_index = __n;
86 
87   memset(__do_not_check, 0, sizeof(__do_not_check));
88 
89   while (__first != __last) {
90     difference_type __new_n = __n;
91     for (__i = __start; __i < __n; ++__i) {
92       if (!__do_not_check[__i]) {
93         if (*__first == __name[__i][__pos]) {
94           if (__pos == (__name[__i].size() - 1)) {
95             __matching_name_index = __i;
96             __do_not_check[__i] = true;
97             if (__i == __start) ++__start;
98             --__check_count;
99             if (__check_count == 0) {
100               ++__first;
101               return __matching_name_index;
102             }
103           }
104           __new_n = __i + 1;
105         }
106         else {
107           __do_not_check[__i] = true;
108           if (__i == __start) ++__start;
109           --__check_count;
110           if (__check_count == 0)
111             return __matching_name_index;
112         }
113       }
114       else {
115         if (__i == __start) ++ __start;
116       }
117     }
118 
119     __n = __new_n;
120     ++__first; ++__pos;
121   }
122 
123   return __matching_name_index;
124 }
125 
126 // __get_formatted_time reads input that is assumed to be formatted
127 // according to the rules for the C strftime function (C standard,
128 // 7.12.3.5).  This function is used to implement the do_get_time
129 // and do_get_date virtual functions, which depend on the locale
130 // specifications for the time and day formats respectively.
131 // Note the catchall default case, intended mainly for the '%Z'
132 // format designator, which does not make sense here since the
133 // representation of timezones is not part of the locale.
134 //
135 // The case branches are implemented either by doing a match using
136 // the appopriate name table or by doing a __get_integer_nogroup.
137 //
138 // 'y' format is assumed to mean that the input represents years
139 // since 1900.  That is, 2002 should be represented as 102.  There
140 // is no century-guessing.
141 //
142 // The match is successful if and only if the second component of the
143 // return value is format_end.
144 
145 // Note that the antepenultimate parameter is being used only to determine
146 // the correct overloading for the calls to __get_integer_nogroup.
147 template <class _InIt1, class _Ch, class _TimeInfo>
148 string::const_iterator _STLP_CALL
_STLP_WEAK(_InIt1 __first,_InIt1 __last,string::const_iterator __format,string::const_iterator __format_end,_Ch *,const _TimeInfo & __table,const ios_base & __s,ios_base::iostate & __err,tm * __t)149 __get_formatted_time _STLP_WEAK (_InIt1 __first,  _InIt1 __last,
150                                  string::const_iterator __format, string::const_iterator __format_end,
151                                  _Ch*, const _TimeInfo& __table,
152                                  const ios_base& __s, ios_base::iostate& __err, tm* __t) {
153   const ctype<_Ch>& __ct = use_facet<ctype<_Ch> >(__s.getloc());
154   typedef basic_string<_Ch, char_traits<_Ch>, allocator<_Ch> > string_type;
155   size_t offset;
156 
157   while (__first != __last && __format != __format_end) {
158     offset = 0;
159     if (*__format == '%') {
160       ++__format;
161       char __c = *__format;
162       if (__c == '#') { //MS extension
163         ++__format;
164         __c = *__format;
165       }
166 
167       switch (__c) {
168         case 'A':
169           offset = 7;
170         case 'a': {
171           size_t __index = __match(__first, __last,
172                                    __table._M_dayname + offset, __table._M_dayname + offset + 7);
173           if (__index == 7)
174             return __format;
175           __t->tm_wday = __STATIC_CAST(int, __index);
176           break;
177         }
178 
179         case 'B':
180           offset = 12;
181         case 'b': {
182           size_t __index = __match(__first, __last,
183                                    __table._M_monthname + offset, __table._M_monthname + offset + 12);
184           if (__index == 12)
185             return __format;
186           __t->tm_mon = __STATIC_CAST(int, __index);
187           break;
188         }
189 
190         case 'd': {
191           bool __pr = __get_decimal_integer(__first, __last, __t->tm_mday, __STATIC_CAST(_Ch*, 0));
192           if (!__pr || __t->tm_mday < 1 || __t->tm_mday > 31) {
193             __err |= ios_base::failbit;
194             return __format;
195           }
196           break;
197         }
198 
199         case 'H': case 'I': {
200           bool __pr = __get_decimal_integer(__first, __last, __t->tm_hour, __STATIC_CAST(_Ch*, 0));
201           if (!__pr)
202             return __format;
203           break;
204         }
205 
206         case 'j': {
207           bool __pr = __get_decimal_integer(__first, __last, __t->tm_yday, __STATIC_CAST(_Ch*, 0));
208           if (!__pr)
209             return __format;
210           break;
211         }
212 
213         case 'm': {
214           bool __pr = __get_decimal_integer(__first, __last, __t->tm_mon, __STATIC_CAST(_Ch*, 0));
215           --__t->tm_mon;
216           if (!__pr || __t->tm_mon < 0 || __t->tm_mon > 11) {
217             __err |= ios_base::failbit;
218             return __format;
219           }
220           break;
221         }
222 
223         case 'M': {
224           bool __pr = __get_decimal_integer(__first, __last, __t->tm_min, __STATIC_CAST(_Ch*, 0));
225           if (!__pr)
226             return __format;
227           break;
228         }
229 
230         case 'p': {
231           size_t __index = __match(__first, __last,
232                                    __table._M_am_pm + 0, __table._M_am_pm + 2);
233           if (__index == 2)
234             return __format;
235           // 12:00 PM <=> 12:00, 12:00 AM <=> 00:00
236           if (__index == 1 && __t->tm_hour != 12 )
237             __t->tm_hour += 12;
238           if (__index == 0 && __t->tm_hour == 12 )
239             __t->tm_hour = 0;
240           break;
241         }
242 
243         case 'S': {
244           bool __pr = __get_decimal_integer(__first, __last, __t->tm_sec, __STATIC_CAST(_Ch*, 0));
245           if (!__pr)
246             return __format;
247           break;
248         }
249 
250         case 'y': {
251           bool __pr = __get_decimal_integer(__first, __last, __t->tm_year, __STATIC_CAST(_Ch*, 0));
252           if (!__pr)
253             return __format;
254           break;
255         }
256 
257         case 'Y': {
258           bool __pr = __get_decimal_integer(__first, __last, __t->tm_year, __STATIC_CAST(_Ch*, 0));
259           __t->tm_year -= 1900;
260           if (!__pr)
261             return __format;
262           break;
263         }
264 
265         default:
266           break;
267       }
268     }
269     else {
270       if (*__first++ != __ct.widen(*__format)) break;
271     }
272 
273     ++__format;
274   }
275 
276   return __format;
277 }
278 
279 template <class _InIt, class _TimeInfo>
280 bool _STLP_CALL
__get_short_or_long_dayname(_InIt & __first,_InIt & __last,const _TimeInfo & __table,tm * __t)281 __get_short_or_long_dayname(_InIt& __first, _InIt& __last, const _TimeInfo& __table, tm* __t) {
282   size_t __index = __match(__first, __last, __table._M_dayname + 0, __table._M_dayname + 14);
283   if (__index != 14) {
284     __t->tm_wday = __STATIC_CAST(int, __index % 7);
285     return true;
286   }
287   return false;
288 }
289 
290 template <class _InIt, class _TimeInfo>
291 bool _STLP_CALL
__get_short_or_long_monthname(_InIt & __first,_InIt & __last,const _TimeInfo & __table,tm * __t)292 __get_short_or_long_monthname(_InIt& __first, _InIt& __last, const _TimeInfo& __table, tm* __t) {
293   size_t __index = __match(__first, __last, __table._M_monthname + 0, __table._M_monthname + 24);
294   if (__index != 24) {
295     __t->tm_mon = __STATIC_CAST(int, __index % 12);
296     return true;
297   }
298   return false;
299 }
300 
301 _STLP_MOVE_TO_STD_NAMESPACE
302 
303 template <class _Ch, class _InIt>
304 _InIt
do_get_date(_InIt __s,_InIt __end,ios_base & __str,ios_base::iostate & __err,tm * __t)305 time_get<_Ch, _InIt>::do_get_date(_InIt __s, _InIt  __end,
306                                   ios_base& __str, ios_base::iostate&  __err,
307                                   tm* __t) const {
308   typedef string::const_iterator string_iterator;
309 
310   string_iterator __format = this->_M_timeinfo._M_date_format.begin();
311   string_iterator __format_end = this->_M_timeinfo._M_date_format.end();
312 
313   string_iterator __result
314     = _STLP_PRIV __get_formatted_time(__s, __end, __format, __format_end,
315                                       __STATIC_CAST(_Ch*, 0), this->_M_timeinfo,
316                                       __str, __err, __t);
317   if (__result == __format_end)
318     __err = ios_base::goodbit;
319   else {
320     __err = ios_base::failbit;
321     if (__s == __end)
322       __err |= ios_base::eofbit;
323   }
324   return __s;
325 }
326 
327 template <class _Ch, class _InIt>
328 _InIt
do_get_time(_InIt __s,_InIt __end,ios_base & __str,ios_base::iostate & __err,tm * __t)329 time_get<_Ch, _InIt>::do_get_time(_InIt __s, _InIt  __end,
330                                   ios_base& __str, ios_base::iostate&  __err,
331                                   tm* __t) const {
332   typedef string::const_iterator string_iterator;
333   string_iterator __format = this->_M_timeinfo._M_time_format.begin();
334   string_iterator __format_end = this->_M_timeinfo._M_time_format.end();
335 
336   string_iterator __result
337     = _STLP_PRIV __get_formatted_time(__s, __end, __format, __format_end,
338                                       __STATIC_CAST(_Ch*, 0), this->_M_timeinfo,
339                                       __str, __err, __t);
340   __err = __result == __format_end ? ios_base::goodbit
341                                    : ios_base::failbit;
342   if (__s == __end)
343     __err |= ios_base::eofbit;
344   return __s;
345 }
346 
347 template <class _Ch, class _InIt>
348 _InIt
do_get_year(_InIt __s,_InIt __end,ios_base &,ios_base::iostate & __err,tm * __t)349 time_get<_Ch, _InIt>::do_get_year(_InIt __s, _InIt  __end,
350                                   ios_base&, ios_base::iostate&  __err,
351                                   tm* __t) const {
352   if (__s == __end) {
353     __err = ios_base::failbit | ios_base::eofbit;
354     return __s;
355   }
356 
357   bool __pr =  _STLP_PRIV __get_decimal_integer(__s, __end, __t->tm_year, __STATIC_CAST(_Ch*, 0));
358   __t->tm_year -= 1900;
359   __err = __pr ? ios_base::goodbit : ios_base::failbit;
360   if (__s == __end)
361     __err |= ios_base::eofbit;
362 
363   return __s;
364 }
365 
366 template <class _Ch, class _InIt>
367 _InIt
do_get_weekday(_InIt __s,_InIt __end,ios_base & __str,ios_base::iostate & __err,tm * __t)368 time_get<_Ch, _InIt>::do_get_weekday(_InIt __s, _InIt  __end,
369                                      ios_base &__str, ios_base::iostate &__err,
370                                      tm *__t) const {
371   bool __result =
372     _STLP_PRIV __get_short_or_long_dayname(__s, __end, this->_M_timeinfo, __t);
373   if (__result)
374     __err = ios_base::goodbit;
375   else {
376     __err = ios_base::failbit;
377     if (__s == __end)
378       __err |= ios_base::eofbit;
379   }
380   return __s;
381 }
382 
383 template <class _Ch, class _InIt>
384 _InIt
do_get_monthname(_InIt __s,_InIt __end,ios_base & __str,ios_base::iostate & __err,tm * __t)385 time_get<_Ch, _InIt>::do_get_monthname(_InIt __s, _InIt  __end,
386                                        ios_base &__str, ios_base::iostate &__err,
387                                        tm *__t) const {
388   bool __result =
389     _STLP_PRIV __get_short_or_long_monthname(__s, __end, this->_M_timeinfo, __t);
390   if (__result)
391     __err = ios_base::goodbit;
392   else {
393     __err = ios_base::failbit;
394     if (__s == __end)
395       __err |= ios_base::eofbit;
396   }
397   return __s;
398 }
399 
400 template<class _Ch, class _OutputIter>
401 _OutputIter
put(_OutputIter __s,ios_base & __f,_Ch __fill,const tm * __tmb,const _Ch * __pat,const _Ch * __pat_end)402 time_put<_Ch,_OutputIter>::put(_OutputIter __s, ios_base& __f, _Ch __fill,
403                                const tm* __tmb, const _Ch* __pat,
404                                const _Ch* __pat_end) const {
405   const ctype<_Ch>& _Ct = use_facet<ctype<_Ch> >(__f.getloc());
406   while (__pat != __pat_end) {
407     char __c = _Ct.narrow(*__pat, 0);
408     if (__c == '%') {
409       char __mod = 0;
410       ++__pat;
411       __c = _Ct.narrow(*__pat++, 0);
412       if (__c == '#') { // MS extension
413         __mod = __c;
414         __c = _Ct.narrow(*__pat++, 0);
415       }
416       __s = do_put(__s, __f, __fill, __tmb, __c, __mod);
417     }
418     else
419       *__s++ = *__pat++;
420   }
421   return __s;
422 }
423 
424 template<class _Ch, class _OutputIter>
425 _OutputIter
do_put(_OutputIter __s,ios_base & __f,_Ch,const tm * __tmb,char __format,char __modifier)426 time_put<_Ch,_OutputIter>::do_put(_OutputIter __s, ios_base& __f, _Ch /* __fill */,
427                                   const tm* __tmb, char __format,
428                                   char __modifier ) const {
429   const ctype<_Ch>& __ct = use_facet<ctype<_Ch> >(__f.getloc());
430   _STLP_BASIC_IOSTRING(_Ch) __buf;
431   _STLP_PRIV __write_formatted_time(__buf, __ct, __format, __modifier, this->_M_timeinfo, __tmb);
432   return copy(__buf.begin(), __buf.end(), __s);
433 }
434 
435 _STLP_END_NAMESPACE
436 
437 #endif /* _STLP_TIME_FACETS_C */
438 
439 // Local Variables:
440 // mode:C++
441 // End:
442