Home | History | Annotate | Download | only in stl
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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