Home | History | Annotate | Download | only in src
      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 
     19 #include "stlport_prefix.h"
     20 
     21 #include <cstdio>
     22 #include <locale>
     23 #include <istream>
     24 
     25 #include "c_locale.h"
     26 #include "acquire_release.h"
     27 
     28 _STLP_BEGIN_NAMESPACE
     29 
     30 _STLP_MOVE_TO_PRIV_NAMESPACE
     31 
     32 // default "C" values for month and day names
     33 
     34 const char default_dayname[][14] = {
     35   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
     36   "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
     37   "Friday", "Saturday"};
     38 
     39 const char default_monthname[][24] = {
     40   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     41   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
     42   "January", "February", "March", "April", "May", "June",
     43   "July", "August", "September", "October", "November", "December"};
     44 
     45 #ifndef _STLP_NO_WCHAR_T
     46 const wchar_t default_wdayname[][14] = {
     47   L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat",
     48   L"Sunday", L"Monday", L"Tuesday", L"Wednesday", L"Thursday",
     49   L"Friday", L"Saturday"};
     50 
     51 const wchar_t default_wmonthname[][24] = {
     52   L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun",
     53   L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec",
     54   L"January", L"February", L"March", L"April", L"May", L"June",
     55   L"July", L"August", L"September", L"October", L"November", L"December"};
     56 #endif
     57 
     58 #if defined (__BORLANDC__)
     59 _Time_Info time_init<char>::_M_timeinfo;
     60 #  ifndef _STLP_NO_WCHAR_T
     61 _WTime_Info time_init<wchar_t>::_M_timeinfo;
     62 #  endif
     63 #endif
     64 
     65 // _Init_time_info: initialize table with
     66 // "C" values (note these are not defined in the C standard, so this
     67 // is somewhat arbitrary).
     68 
     69 static void _Init_timeinfo_base(_Time_Info_Base& table) {
     70   table._M_time_format = "%H:%M:%S";
     71   table._M_date_format = "%m/%d/%y";
     72   table._M_date_time_format = "%m/%d/%y";
     73 }
     74 
     75 static void _Init_timeinfo(_Time_Info& table) {
     76   int i;
     77   for (i = 0; i < 14; ++i)
     78     table._M_dayname[i] = default_dayname[i];
     79   for (i = 0; i < 24; ++i)
     80     table._M_monthname[i] = default_monthname[i];
     81   table._M_am_pm[0] = "AM";
     82   table._M_am_pm[1] = "PM";
     83   _Init_timeinfo_base(table);
     84 }
     85 
     86 #ifndef _STLP_NO_WCHAR_T
     87 static void _Init_timeinfo(_WTime_Info& table) {
     88   int i;
     89   for (i = 0; i < 14; ++i)
     90     table._M_dayname[i] = default_wdayname[i];
     91   for (i = 0; i < 24; ++i)
     92     table._M_monthname[i] = default_wmonthname[i];
     93   table._M_am_pm[0] = L"AM";
     94   table._M_am_pm[1] = L"PM";
     95   _Init_timeinfo_base(table);
     96 }
     97 #endif
     98 
     99 static void _Init_timeinfo_base(_Time_Info_Base& table, _Locale_time * time) {
    100   table._M_time_format = _Locale_t_fmt(time);
    101   if ( table._M_time_format == "%T" ) {
    102     table._M_time_format = "%H:%M:%S";
    103   } else if ( table._M_time_format == "%r" ) {
    104     table._M_time_format = "%I:%M:%S %p";
    105   } else if ( table._M_time_format == "%R" ) {
    106     table._M_time_format = "%H:%M";
    107   }
    108   table._M_date_format = _Locale_d_fmt(time);
    109   table._M_date_time_format = _Locale_d_t_fmt(time);
    110   table._M_long_date_format = _Locale_long_d_fmt(time);
    111   table._M_long_date_time_format = _Locale_long_d_t_fmt(time);
    112 }
    113 
    114 static void _Init_timeinfo(_Time_Info& table, _Locale_time * time) {
    115   int i;
    116   for (i = 0; i < 7; ++i)
    117     table._M_dayname[i] = _Locale_abbrev_dayofweek(time, i);
    118   for (i = 0; i < 7; ++i)
    119     table._M_dayname[i+7] = _Locale_full_dayofweek(time, i);
    120   for (i = 0; i < 12; ++i)
    121     table._M_monthname[i] = _Locale_abbrev_monthname(time, i);
    122   for (i = 0; i < 12; ++i)
    123     table._M_monthname[i+12] = _Locale_full_monthname(time, i);
    124   table._M_am_pm[0] = _Locale_am_str(time);
    125   table._M_am_pm[1] = _Locale_pm_str(time);
    126   _Init_timeinfo_base(table, time);
    127 }
    128 
    129 #ifndef _STLP_NO_WCHAR_T
    130 static void _Init_timeinfo(_WTime_Info& table, _Locale_time * time) {
    131   wchar_t buf[128];
    132   int i;
    133   for (i = 0; i < 7; ++i)
    134     table._M_dayname[i] = _WLocale_abbrev_dayofweek(time, i, _STLP_ARRAY_AND_SIZE(buf));
    135   for (i = 0; i < 7; ++i)
    136     table._M_dayname[i+7] = _WLocale_full_dayofweek(time, i, _STLP_ARRAY_AND_SIZE(buf));
    137   for (i = 0; i < 12; ++i)
    138     table._M_monthname[i] = _WLocale_abbrev_monthname(time, i, _STLP_ARRAY_AND_SIZE(buf));
    139   for (i = 0; i < 12; ++i)
    140     table._M_monthname[i+12] = _WLocale_full_monthname(time, i, _STLP_ARRAY_AND_SIZE(buf));
    141   table._M_am_pm[0] = _WLocale_am_str(time, _STLP_ARRAY_AND_SIZE(buf));
    142   table._M_am_pm[1] = _WLocale_pm_str(time, _STLP_ARRAY_AND_SIZE(buf));
    143   _Init_timeinfo_base(table, time);
    144 }
    145 #endif
    146 
    147 template <class _Ch, class _TimeInfo>
    148 void __subformat(_STLP_BASIC_IOSTRING(_Ch) &buf, const ctype<_Ch>& ct,
    149                  const string& format, const _TimeInfo& table, const tm* t) {
    150   const char * cp = format.data();
    151   const char * cp_end = cp + format.size();
    152   while (cp != cp_end) {
    153     if (*cp == '%') {
    154       char mod = 0;
    155       ++cp;
    156       if (*cp == '#') {
    157         mod = *cp; ++cp;
    158       }
    159       __write_formatted_timeT(buf, ct, *cp++, mod, table, t);
    160     } else
    161       buf.append(1, *cp++);
    162   }
    163 }
    164 
    165 static void __append(__iostring &buf, const string& name)
    166 { buf.append(name.data(), name.data() + name.size()); }
    167 
    168 static void __append(__iowstring &buf, const wstring& name)
    169 { buf.append(name.data(), name.data() + name.size()); }
    170 
    171 static void __append(__iostring &buf, char *first, char *last, const ctype<char>& /* ct */)
    172 { buf.append(first, last); }
    173 
    174 static void __append(__iowstring &buf, char *first, char *last, const ctype<wchar_t>& ct) {
    175   wchar_t _wbuf[64];
    176   ct.widen(first, last, _wbuf);
    177   buf.append(_wbuf, _wbuf + (last - first));
    178 }
    179 
    180 #if defined (__GNUC__)
    181 /* The number of days from the first day of the first ISO week of this
    182    year to the year day YDAY with week day WDAY.  ISO weeks start on
    183    Monday; the first ISO week has the year's first Thursday.  YDAY may
    184    be as small as YDAY_MINIMUM.  */
    185 #  define __ISO_WEEK_START_WDAY 1 /* Monday */
    186 #  define __ISO_WEEK1_WDAY 4 /* Thursday */
    187 #  define __YDAY_MINIMUM (-366)
    188 #  define __TM_YEAR_BASE 1900
    189 static int
    190 __iso_week_days(int yday, int wday) {
    191   /* Add enough to the first operand of % to make it nonnegative.  */
    192   int big_enough_multiple_of_7 = (-__YDAY_MINIMUM / 7 + 2) * 7;
    193   return (yday
    194           - (yday - wday + __ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
    195           + __ISO_WEEK1_WDAY - __ISO_WEEK_START_WDAY);
    196 }
    197 
    198 #  define __is_leap(year)\
    199   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
    200 
    201 #endif
    202 
    203 #define __hour12(hour) \
    204   (((hour) % 12 == 0) ? (12) : (hour) % 12)
    205 
    206 #if !defined (_STLP_USE_SAFE_STRING_FUNCTIONS)
    207 #  define _STLP_SPRINTF sprintf
    208 #else
    209 #  define _STLP_SPRINTF sprintf_s
    210 #endif
    211 
    212 template <class _Ch, class _TimeInfo>
    213 void _STLP_CALL __write_formatted_timeT(_STLP_BASIC_IOSTRING(_Ch) &buf,
    214                                         const ctype<_Ch>& ct,
    215                                         char format, char modifier,
    216                                         const _TimeInfo& table, const tm* t) {
    217   char _buf[64];
    218   char *_bend;
    219 
    220   switch (format) {
    221     case 'a':
    222       __append(buf, table._M_dayname[t->tm_wday]);
    223       break;
    224 
    225     case 'A':
    226       __append(buf, table._M_dayname[t->tm_wday + 7]);
    227       break;
    228 
    229     case 'b':
    230       __append(buf, table._M_monthname[t->tm_mon]);
    231       break;
    232 
    233     case 'B':
    234       __append(buf, table._M_monthname[t->tm_mon + 12]);
    235       break;
    236 
    237     case 'c':
    238       __subformat(buf, ct, (modifier != '#') ? table._M_date_time_format
    239                                              : table._M_long_date_time_format, table, t);
    240       break;
    241 
    242     case 'd':
    243       _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_mday);
    244       __append(buf, _buf, ((long)t->tm_mday < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
    245       break;
    246 
    247     case 'e':
    248       _STLP_SPRINTF(_buf, "%2ld", (long)t->tm_mday);
    249       __append(buf, _buf, _buf + 2, ct);
    250       break;
    251 
    252     case 'H':
    253       _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_hour);
    254       __append(buf, _buf, ((long)t->tm_hour < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
    255       break;
    256 
    257     case 'I':
    258       _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)__hour12(t->tm_hour));
    259       __append(buf, _buf, ((long)__hour12(t->tm_hour) < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
    260       break;
    261 
    262     case 'j':
    263       _bend = __write_integer(_buf, 0, (long)((long)t->tm_yday + 1));
    264       __append(buf, _buf, _bend, ct);
    265       break;
    266 
    267     case 'm':
    268       _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_mon + 1);
    269       __append(buf, _buf, ((long)(t->tm_mon + 1) < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
    270       break;
    271 
    272     case 'M':
    273       _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_min);
    274       __append(buf, _buf, ((long)t->tm_min < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
    275       break;
    276 
    277     case 'p':
    278       __append(buf, table._M_am_pm[t->tm_hour / 12]);
    279       break;
    280 
    281     case 'S': // pad with zeros
    282        _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_sec);
    283        __append(buf, _buf, ((long)t->tm_sec < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
    284        break;
    285 
    286     case 'U':
    287       _bend = __write_integer(_buf, 0, long((t->tm_yday - t->tm_wday + 7) / 7));
    288       __append(buf, _buf, _bend, ct);
    289       break;
    290 
    291     case 'w':
    292       _bend = __write_integer(_buf, 0, (long)t->tm_wday);
    293       __append(buf, _buf, _bend, ct);
    294       break;
    295 
    296     case 'W':
    297       _bend = __write_integer(_buf, 0,
    298                              (long)(t->tm_wday == 0 ? (t->tm_yday + 1) / 7 :
    299                                                       (t->tm_yday + 8 - t->tm_wday) / 7));
    300       __append(buf, _buf, _bend, ct);
    301       break;
    302 
    303     case'x':
    304       __subformat(buf, ct, (modifier != '#') ? table._M_date_format
    305                                              : table._M_long_date_format, table, t);
    306       break;
    307 
    308     case 'X':
    309       __subformat(buf, ct, table._M_time_format, table, t);
    310       break;
    311 
    312     case 'y':
    313       _bend = __write_integer(_buf, 0, (long)((long)(t->tm_year + 1900) % 100));
    314       __append(buf, _buf, _bend, ct);
    315       break;
    316 
    317     case 'Y':
    318       _bend = __write_integer(_buf, 0, (long)((long)t->tm_year + 1900));
    319       __append(buf, _buf, _bend, ct);
    320       break;
    321 
    322     case '%':
    323       buf.append(1, ct.widen('%'));
    324       break;
    325 
    326 #if defined (__GNUC__)
    327       // fbp : at least on SUN
    328 #  if defined (_STLP_UNIX) && !defined (__linux__)
    329 #    define __USE_BSD 1
    330 #  endif
    331 
    332    /*********************************************
    333     *     JGS, handle various extensions        *
    334     *********************************************/
    335 
    336     case 'h': /* POSIX.2 extension */
    337       // same as 'b', abbrev month name
    338       __append(buf, table._M_monthname[t->tm_mon]);
    339       break;
    340     case 'C': /* POSIX.2 extension */
    341       // same as 'd', the day
    342       _STLP_SPRINTF(_buf, "%2ld", (long)t->tm_mday);
    343       __append(buf, _buf, _buf + 2, ct);
    344       break;
    345 
    346     case 'D': /* POSIX.2 extension */
    347       // same as 'x'
    348       __subformat(buf, ct, table._M_date_format, table, t);
    349       break;
    350 
    351     case 'k': /* GNU extension */
    352       _STLP_SPRINTF(_buf, "%2ld", (long)t->tm_hour);
    353       __append(buf, _buf, _buf + 2, ct);
    354       break;
    355 
    356     case 'l': /* GNU extension */
    357       _STLP_SPRINTF(_buf, "%2ld", (long)t->tm_hour % 12);
    358       __append(buf, _buf, _buf + 2, ct);
    359       break;
    360 
    361     case 'n': /* POSIX.2 extension */
    362       buf.append(1, ct.widen('\n'));
    363       break;
    364 
    365     case 'R': /* GNU extension */
    366       __subformat(buf, ct, "%H:%M", table, t);
    367       break;
    368 
    369     case 'r': /* POSIX.2 extension */
    370       __subformat(buf, ct, "%I:%M:%S %p", table, t);
    371       break;
    372 
    373     case 'T': /* POSIX.2 extension.  */
    374       __subformat(buf, ct, "%H:%M:%S", table, t);
    375       break;
    376 
    377     case 't': /* POSIX.2 extension.  */
    378       buf.append(1, ct.widen('\t'));
    379 
    380     case 'u': /* POSIX.2 extension.  */
    381       _bend = __write_integer(_buf, 0, long((t->tm_wday - 1 + 7)) % 7 + 1);
    382       __append(buf, _buf, _bend, ct);
    383       break;
    384 
    385     case 's': {
    386       time_t __t = mktime(__CONST_CAST(tm*, t));
    387       _bend = __write_integer(_buf, 0, (long)__t );
    388       __append(buf, _buf, _bend, ct);
    389       break;
    390     }
    391     case 'g': /* GNU extension */
    392     case 'G': {
    393       int year = t->tm_year + __TM_YEAR_BASE;
    394       int days = __iso_week_days (t->tm_yday, t->tm_wday);
    395       if (days < 0) {
    396         /* This ISO week belongs to the previous year.  */
    397         year--;
    398         days = __iso_week_days (t->tm_yday + (365 + __is_leap (year)), t->tm_wday);
    399       }
    400       else {
    401         int d = __iso_week_days (t->tm_yday - (365 + __is_leap (year)), t->tm_wday);
    402         if (0 <= d) {
    403           /* This ISO week belongs to the next year.  */
    404           ++year;
    405           days = d;
    406         }
    407       }
    408       long val;
    409       switch (format) {
    410       case 'g':
    411         val = (long)(year % 100 + 100) % 100;
    412         break;
    413       case 'G':
    414         val = (long)year;
    415         break;
    416       default:
    417         val = (long)days / 7 + 1;
    418         break;
    419       }
    420       _bend = __write_integer(_buf, 0, val);
    421       __append(buf, _buf, _bend, ct);
    422       break;
    423     }
    424 
    425 #  if defined (_STLP_USE_GLIBC)
    426     case 'z':   /* GNU extension.  */
    427       if (t->tm_isdst < 0)
    428         break;
    429       {
    430         int diff;
    431 #    if defined (__USE_BSD) || defined (__BEOS__)
    432         diff = t->tm_gmtoff;
    433 #    else
    434         diff = t->__tm_gmtoff;
    435 #    endif
    436         if (diff < 0) {
    437           buf.append(1, ct.widen('-'));
    438           diff = -diff;
    439         } else
    440           buf.append(1, ct.widen('+'));
    441         diff /= 60;
    442         _STLP_SPRINTF(_buf, "%.4d", (diff / 60) * 100 + diff % 60);
    443         __append(buf, _buf, _buf + 4, ct);
    444         break;
    445       }
    446 #  endif /* __GLIBC__ */
    447 #endif /* __GNUC__ */
    448 
    449     default:
    450       break;
    451   }
    452 }
    453 
    454 void _STLP_CALL __write_formatted_time(__iostring &buf, const ctype<char>& ct,
    455                                        char format, char modifier,
    456                                        const _Time_Info& table, const tm* t)
    457 { __write_formatted_timeT(buf, ct, format, modifier, table, t); }
    458 
    459 void _STLP_CALL __write_formatted_time(__iowstring &buf, const ctype<wchar_t>& ct,
    460                                        char format, char modifier,
    461                                        const _WTime_Info& table, const tm* t)
    462 { __write_formatted_timeT(buf, ct, format, modifier, table, t); }
    463 
    464 static time_base::dateorder __get_date_order(_Locale_time* time) {
    465   const char * fmt = _Locale_d_fmt(time);
    466   char first, second, third;
    467 
    468   while (*fmt != 0 && *fmt != '%') ++fmt;
    469   if (*fmt == 0)
    470     return time_base::no_order;
    471   first = *++fmt;
    472   while (*fmt != 0 && *fmt != '%') ++fmt;
    473   if (*fmt == 0)
    474     return time_base::no_order;
    475   second = *++fmt;
    476   while (*fmt != 0 && *fmt != '%') ++fmt;
    477   if (*fmt == 0)
    478     return time_base::no_order;
    479   third = *++fmt;
    480 
    481   switch (first) {
    482     case 'd':
    483       return (second == 'm' && third == 'y') ? time_base::dmy
    484                                              : time_base::no_order;
    485     case 'm':
    486       return (second == 'd' && third == 'y') ? time_base::mdy
    487                                              : time_base::no_order;
    488     case 'y':
    489       switch (second) {
    490         case 'd':
    491           return third == 'm' ? time_base::ydm : time_base::no_order;
    492         case 'm':
    493           return third == 'd' ? time_base::ymd : time_base::no_order;
    494         default:
    495           return time_base::no_order;
    496       }
    497     default:
    498       return time_base::no_order;
    499   }
    500 }
    501 
    502 time_init<char>::time_init()
    503   : _M_dateorder(time_base::no_order)
    504 { _Init_timeinfo(_M_timeinfo); }
    505 
    506 time_init<char>::time_init(const char* __name) {
    507   if (!__name)
    508     locale::_M_throw_on_null_name();
    509 
    510   int __err_code;
    511   char buf[_Locale_MAX_SIMPLE_NAME];
    512   _Locale_time *__time = __acquire_time(__name, buf, 0, &__err_code);
    513   if (!__time)
    514     locale::_M_throw_on_creation_failure(__err_code, __name, "time");
    515 
    516   _Init_timeinfo(this->_M_timeinfo, __time);
    517   _M_dateorder = __get_date_order(__time);
    518   __release_time(__time);
    519 }
    520 
    521 time_init<char>::time_init(_Locale_time *__time) {
    522   _Init_timeinfo(this->_M_timeinfo, __time);
    523   _M_dateorder = __get_date_order(__time);
    524 }
    525 
    526 #ifndef _STLP_NO_WCHAR_T
    527 time_init<wchar_t>::time_init()
    528   : _M_dateorder(time_base::no_order)
    529 { _Init_timeinfo(_M_timeinfo); }
    530 
    531 time_init<wchar_t>::time_init(const char* __name) {
    532   if (!__name)
    533     locale::_M_throw_on_null_name();
    534 
    535   int __err_code;
    536   char buf[_Locale_MAX_SIMPLE_NAME];
    537   _Locale_time *__time = __acquire_time(__name, buf, 0, &__err_code);
    538   if (!__time)
    539     locale::_M_throw_on_creation_failure(__err_code, __name, "time");
    540 
    541   _Init_timeinfo(this->_M_timeinfo, __time);
    542   _M_dateorder = __get_date_order(__time);
    543   __release_time(__time);
    544 }
    545 
    546 time_init<wchar_t>::time_init(_Locale_time *__time) {
    547   _Init_timeinfo(this->_M_timeinfo, __time);
    548   _M_dateorder = __get_date_order(__time);
    549 }
    550 #endif
    551 
    552 _STLP_MOVE_TO_STD_NAMESPACE
    553 
    554 #if !defined (_STLP_NO_FORCE_INSTANTIATE)
    555 template class time_get<char, istreambuf_iterator<char, char_traits<char> > >;
    556 template class time_put<char, ostreambuf_iterator<char, char_traits<char> > >;
    557 
    558 #  ifndef _STLP_NO_WCHAR_T
    559 template class time_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t> > >;
    560 template class time_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t> > >;
    561 #  endif
    562 
    563 #endif
    564 
    565 _STLP_END_NAMESPACE
    566