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
_Init_timeinfo_base(_Time_Info_Base & table)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
_Init_timeinfo(_Time_Info & table)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
_Init_timeinfo(_WTime_Info & table)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
_Init_timeinfo_base(_Time_Info_Base & table,_Locale_time * time)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
_Init_timeinfo(_Time_Info & table,_Locale_time * time)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
_Init_timeinfo(_WTime_Info & table,_Locale_time * time)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>
__subformat(_STLP_BASIC_IOSTRING (_Ch)& buf,const ctype<_Ch> & ct,const string & format,const _TimeInfo & table,const tm * t)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
__append(__iostring & buf,const string & name)165 static void __append(__iostring &buf, const string& name)
166 { buf.append(name.data(), name.data() + name.size()); }
167
__append(__iowstring & buf,const wstring & name)168 static void __append(__iowstring &buf, const wstring& name)
169 { buf.append(name.data(), name.data() + name.size()); }
170
__append(__iostring & buf,char * first,char * last,const ctype<char> &)171 static void __append(__iostring &buf, char *first, char *last, const ctype<char>& /* ct */)
172 { buf.append(first, last); }
173
__append(__iowstring & buf,char * first,char * last,const ctype<wchar_t> & ct)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
__iso_week_days(int yday,int wday)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>
__write_formatted_timeT(_STLP_BASIC_IOSTRING (_Ch)& buf,const ctype<_Ch> & ct,char format,char modifier,const _TimeInfo & table,const tm * t)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
__write_formatted_time(__iostring & buf,const ctype<char> & ct,char format,char modifier,const _Time_Info & table,const tm * t)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
__write_formatted_time(__iowstring & buf,const ctype<wchar_t> & ct,char format,char modifier,const _WTime_Info & table,const tm * t)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
__get_date_order(_Locale_time * time)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
time_init()502 time_init<char>::time_init()
503 : _M_dateorder(time_base::no_order)
504 { _Init_timeinfo(_M_timeinfo); }
505
time_init(const char * __name)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
time_init(_Locale_time * __time)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
time_init()527 time_init<wchar_t>::time_init()
528 : _M_dateorder(time_base::no_order)
529 { _Init_timeinfo(_M_timeinfo); }
530
time_init(const char * __name)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
time_init(_Locale_time * __time)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