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