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
namespace {
166
167
void __append(__iostring &buf, const string& name)
168
{ buf.append(name.data(), name.data() + name.size()); }
169
170
#ifndef _STLP_NO_WCHAR_T
171
void __append(__iowstring &buf, const wstring& name)
172
{ buf.append(name.data(), name.data() + name.size()); }
173
#endif
174
175
void __append(__iostring &buf, char *first, char *last, const ctype<char>& /* ct */)
176
{ buf.append(first, last); }
177
178
#ifndef _STLP_NO_WCHAR_T
179
void __append(__iowstring &buf, char *first, char *last, const ctype<wchar_t>& ct) {
180
  wchar_t _wbuf[64];
181
  ct.widen(first, last, _wbuf);
182
  buf.append(_wbuf, _wbuf + (last - first));
183
}
184
#endif
185
186
} // end anonymous namespace
187
188
#if defined (__GNUC__)
189
/* The number of days from the first day of the first ISO week of this
190
   year to the year day YDAY with week day WDAY.  ISO weeks start on
191
   Monday; the first ISO week has the year's first Thursday.  YDAY may
192
   be as small as YDAY_MINIMUM.  */
193
#  define __ISO_WEEK_START_WDAY 1 /* Monday */
194
#  define __ISO_WEEK1_WDAY 4 /* Thursday */
195
#  define __YDAY_MINIMUM (-366)
196
#  define __TM_YEAR_BASE 1900
197
static int
198
__iso_week_days(int yday, int wday) {
199
  /* Add enough to the first operand of % to make it nonnegative.  */
200
  int big_enough_multiple_of_7 = (-__YDAY_MINIMUM / 7 + 2) * 7;
201
  return (yday
202
          - (yday - wday + __ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
203
          + __ISO_WEEK1_WDAY - __ISO_WEEK_START_WDAY);
204
}
205
206
#  define __is_leap(year)\
207
  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
208
209
#endif
210
211
#define __hour12(hour) \
212
  (((hour) % 12 == 0) ? (12) : (hour) % 12)
213
214
#if !defined (_STLP_USE_SAFE_STRING_FUNCTIONS)
215
#  define _STLP_SPRINTF sprintf
216
#else
217
#  define _STLP_SPRINTF sprintf_s
218
#endif
219
220
template <class _Ch, class _TimeInfo>
221
void _STLP_CALL __write_formatted_timeT(_STLP_BASIC_IOSTRING(_Ch) &buf,
222
                                        const ctype<_Ch>& ct,
223
                                        char format, char modifier,
224
                                        const _TimeInfo& table, const tm* t) {
225
  char _buf[64];
226
  char *_bend;
227
228
  switch (format) {
229
    case 'a':
230
      __append(buf, table._M_dayname[t->tm_wday]);
231
      break;
232
233
    case 'A':
234
      __append(buf, table._M_dayname[t->tm_wday + 7]);
235
      break;
236
237
    case 'b':
238
      __append(buf, table._M_monthname[t->tm_mon]);
239
      break;
240
241
    case 'B':
242
      __append(buf, table._M_monthname[t->tm_mon + 12]);
243
      break;
244
245
    case 'c':
246
      __subformat(buf, ct, (modifier != '#') ? table._M_date_time_format
247
                                             : table._M_long_date_time_format, table, t);
248
      break;
249
250
    case 'd':
251
      _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_mday);
252
      __append(buf, _buf, ((long)t->tm_mday < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
253
      break;
254
255
    case 'e':
256
      _STLP_SPRINTF(_buf, "%2ld", (long)t->tm_mday);
257
      __append(buf, _buf, _buf + 2, ct);
258
      break;
259
260
    case 'H':
261
      _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_hour);
262
      __append(buf, _buf, ((long)t->tm_hour < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
263
      break;
264
265
    case 'I':
266
      _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)__hour12(t->tm_hour));
267
      __append(buf, _buf, ((long)__hour12(t->tm_hour) < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
268
      break;
269
270
    case 'j':
271
	{
272
      long yday = (long)((long)t->tm_yday + 1);
273
      _STLP_SPRINTF(_buf, (modifier != '#') ? "%.3ld" : "%ld", yday);
274
      __append(buf, _buf, (yday < 10L && modifier == '#') ? _buf + 1 : ((yday < 100L && modifier == '#') ? _buf + 2 : _buf + 3), ct);
275
      break;
276
    }
277
278
    case 'm':
279
      _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_mon + 1);
280
      __append(buf, _buf, ((long)(t->tm_mon + 1) < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
281
      break;
282
283
    case 'M':
284
      _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_min);
285
      __append(buf, _buf, ((long)t->tm_min < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
286
      break;
287
288
    case 'p':
289
      __append(buf, table._M_am_pm[t->tm_hour / 12]);
290
      break;
291
292
    case 'S': // pad with zeros
293
       _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)t->tm_sec);
294
       __append(buf, _buf, ((long)t->tm_sec < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
295
       break;
296
297
    case 'U':
298
      _bend = __write_integer(_buf, 0, long((t->tm_yday - t->tm_wday + 7) / 7));
299
      __append(buf, _buf, _bend, ct);
300
      break;
301
302
    case 'w':
303
      _bend = __write_integer(_buf, 0, (long)t->tm_wday);
304
      __append(buf, _buf, _bend, ct);
305
      break;
306
307
    case 'W':
308
      _bend = __write_integer(_buf, 0,
309
                             (long)(t->tm_wday == 0 ? (t->tm_yday + 1) / 7 :
310
                                                      (t->tm_yday + 8 - t->tm_wday) / 7));
311
      __append(buf, _buf, _bend, ct);
312
      break;
313
314
    case'x':
315
      __subformat(buf, ct, (modifier != '#') ? table._M_date_format
316
                                             : table._M_long_date_format, table, t);
317
      break;
318
319
    case 'X':
320
      __subformat(buf, ct, table._M_time_format, table, t);
321
      break;
322
323
    case 'y':
324
      _STLP_SPRINTF(_buf, (modifier != '#') ? "%.2ld" : "%ld", (long)(t->tm_year % 100));
325
      __append(buf, _buf, ((long)(t->tm_year % 100) < 10L && modifier == '#') ? _buf + 1 : _buf + 2, ct);
326
      break;
327
328
    case 'Y':
329
      _bend = __write_integer(_buf, 0, (long)((long)t->tm_year + 1900));
330
      __append(buf, _buf, _bend, ct);
331
      break;
332
333
    case '%':
334
      buf.append(1, ct.widen('%'));
335
      break;
336
337
#if defined (__GNUC__)
338
      // fbp : at least on SUN
339
#  if defined (_STLP_UNIX) && !defined (__linux__)
340
#    define __USE_BSD 1
341
#  endif
342
343
   /*********************************************
344
    *     JGS, handle various extensions        *
345
    *********************************************/
346
347
    case 'h': /* POSIX.2 extension */
348
      // same as 'b', abbrev month name
349
      __append(buf, table._M_monthname[t->tm_mon]);
350
      break;
351
    case 'C': /* POSIX.2 extension */
352
      // same as 'd', the day
353
      _STLP_SPRINTF(_buf, "%2ld", (long)t->tm_mday);
354
      __append(buf, _buf, _buf + 2, ct);
355
      break;
356
357
    case 'D': /* POSIX.2 extension */
358
      // same as 'x'
359
      __subformat(buf, ct, table._M_date_format, table, t);
360
      break;
361
362
    case 'k': /* GNU extension */
363
      _STLP_SPRINTF(_buf, "%2ld", (long)t->tm_hour);
364
      __append(buf, _buf, _buf + 2, ct);
365
      break;
366
367
    case 'l': /* GNU extension */
368
      _STLP_SPRINTF(_buf, "%2ld", (long)t->tm_hour % 12);
369
      __append(buf, _buf, _buf + 2, ct);
370
      break;
371
372
    case 'n': /* POSIX.2 extension */
373
      buf.append(1, ct.widen('\n'));
374
      break;
375
376
    case 'R': /* GNU extension */
377
      __subformat(buf, ct, "%H:%M", table, t);
378
      break;
379
380
    case 'r': /* POSIX.2 extension */
381
      __subformat(buf, ct, "%I:%M:%S %p", table, t);
382
      break;
383
384
    case 'T': /* POSIX.2 extension.  */
385
      __subformat(buf, ct, "%H:%M:%S", table, t);
386
      break;
387
388
    case 't': /* POSIX.2 extension.  */
389
      buf.append(1, ct.widen('\t'));
390
391
    case 'u': /* POSIX.2 extension.  */
392
      _bend = __write_integer(_buf, 0, long((t->tm_wday - 1 + 7)) % 7 + 1);
393
      __append(buf, _buf, _bend, ct);
394
      break;
395
396
    case 's': {
397
      time_t __t = mktime(__CONST_CAST(tm*, t));
398
      _bend = __write_integer(_buf, 0, (long)__t );
399
      __append(buf, _buf, _bend, ct);
400
      break;
401
    }
402
    case 'g': /* GNU extension */
403
    case 'G': {
404
      int year = t->tm_year + __TM_YEAR_BASE;
405
      int days = __iso_week_days (t->tm_yday, t->tm_wday);
406
      if (days < 0) {
407
        /* This ISO week belongs to the previous year.  */
408
        year--;
409
        days = __iso_week_days (t->tm_yday + (365 + __is_leap (year)), t->tm_wday);
410
      }
411
      else {
412
        int d = __iso_week_days (t->tm_yday - (365 + __is_leap (year)), t->tm_wday);
413
        if (0 <= d) {
414
          /* This ISO week belongs to the next year.  */
415
          ++year;
416
          days = d;
417
        }
418
      }
419
      long val;
420
      switch (format) {
421
      case 'g':
422
        val = (long)(year % 100 + 100) % 100;
423
        break;
424
      case 'G':
425
        val = (long)year;
426
        break;
427
      default:
428
        val = (long)days / 7 + 1;
429
        break;
430
      }
431
      _bend = __write_integer(_buf, 0, val);
432
      __append(buf, _buf, _bend, ct);
433
      break;
434
    }
435
436
#  if defined (_STLP_USE_GLIBC)
437
    case 'z':   /* GNU extension.  */
438
      if (t->tm_isdst < 0)
439
        break;
440
      {
441
        int diff;
442
#    if defined (__USE_BSD) || defined (__BEOS__)
443
        diff = t->tm_gmtoff;
444
#    else
445
        diff = t->__tm_gmtoff;
446
#    endif
447
        if (diff < 0) {
448
          buf.append(1, ct.widen('-'));
449
          diff = -diff;
450
        } else
451
          buf.append(1, ct.widen('+'));
452
        diff /= 60;
453
        _STLP_SPRINTF(_buf, "%.4d", (diff / 60) * 100 + diff % 60);
454
        __append(buf, _buf, _buf + 4, ct);
455
        break;
456
      }
457
#  endif /* __GLIBC__ */
458
#endif /* __GNUC__ */
459
460
    default:
461
      break;
462
  }
463
}
464
465
void _STLP_CALL __write_formatted_time(__iostring &buf, const ctype<char>& ct,
466
                                       char format, char modifier,
467
                                       const _Time_Info& table, const tm* t)
468
{ __write_formatted_timeT(buf, ct, format, modifier, table, t); }
469
470
#ifndef _STLP_NO_WCHAR_T
471
void _STLP_CALL __write_formatted_time(__iowstring &buf, const ctype<wchar_t>& ct,
472
                                       char format, char modifier,
473
                                       const _WTime_Info& table, const tm* t)
474
{ __write_formatted_timeT(buf, ct, format, modifier, table, t); }
475
#endif
476
477
static time_base::dateorder __get_date_order(_Locale_time* time) {
478
  const char * fmt = _Locale_d_fmt(time);
479
  char first, second, third;
480
481
  while (*fmt != 0 && *fmt != '%') ++fmt;
482
  if (*fmt == 0)
483
    return time_base::no_order;
484
  first = *++fmt;
485
  while (*fmt != 0 && *fmt != '%') ++fmt;
486
  if (*fmt == 0)
487
    return time_base::no_order;
488
  second = *++fmt;
489
  while (*fmt != 0 && *fmt != '%') ++fmt;
490
  if (*fmt == 0)
491
    return time_base::no_order;
492
  third = *++fmt;
493
494
  switch (first) {
495
    case 'd':
496
      return (second == 'm' && third == 'y') ? time_base::dmy
497
                                             : time_base::no_order;
498
    case 'm':
499
      return (second == 'd' && third == 'y') ? time_base::mdy
500
                                             : time_base::no_order;
501
    case 'y':
502
      switch (second) {
503
        case 'd':
504
          return third == 'm' ? time_base::ydm : time_base::no_order;
505
        case 'm':
506
          return third == 'd' ? time_base::ymd : time_base::no_order;
507
        default:
508
          return time_base::no_order;
509
      }
510
    default:
511
      return time_base::no_order;
512
  }
513
}
514
515
time_init<char>::time_init()
516
  : _M_dateorder(time_base::no_order)
517
{ _Init_timeinfo(_M_timeinfo); }
518
519
time_init<char>::time_init(const char* __name) {
520
  if (!__name)
521
    locale::_M_throw_on_null_name();
522
523
  int __err_code;
524
  char buf[_Locale_MAX_SIMPLE_NAME];
525
  _Locale_time *__time = __acquire_time(__name, buf, 0, &__err_code);
526
  if (!__time)
527
    locale::_M_throw_on_creation_failure(__err_code, __name, "time");
528
529
  _Init_timeinfo(this->_M_timeinfo, __time);
530
  _M_dateorder = __get_date_order(__time);
531
  __release_time(__time);
532
}
533
534
time_init<char>::time_init(_Locale_time *__time) {
535
  _Init_timeinfo(this->_M_timeinfo, __time);
536
  _M_dateorder = __get_date_order(__time);
537
}
538
539
#ifndef _STLP_NO_WCHAR_T
540
time_init<wchar_t>::time_init()
541
  : _M_dateorder(time_base::no_order)
542
{ _Init_timeinfo(_M_timeinfo); }
543
544
time_init<wchar_t>::time_init(const char* __name) {
545
  if (!__name)
546
    locale::_M_throw_on_null_name();
547
548
  int __err_code;
549
  char buf[_Locale_MAX_SIMPLE_NAME];
550
  _Locale_time *__time = __acquire_time(__name, buf, 0, &__err_code);
551
  if (!__time)
552
    locale::_M_throw_on_creation_failure(__err_code, __name, "time");
553
554
  _Init_timeinfo(this->_M_timeinfo, __time);
555
  _M_dateorder = __get_date_order(__time);
556
  __release_time(__time);
557
}
558
559
time_init<wchar_t>::time_init(_Locale_time *__time) {
560
  _Init_timeinfo(this->_M_timeinfo, __time);
561
  _M_dateorder = __get_date_order(__time);
562
}
563
#endif
564
565
_STLP_MOVE_TO_STD_NAMESPACE
566
567
#if !defined (_STLP_NO_FORCE_INSTANTIATE)
568
template class time_get<char, istreambuf_iterator<char, char_traits<char> > >;
569
template class time_put<char, ostreambuf_iterator<char, char_traits<char> > >;
570
571
#  ifndef _STLP_NO_WCHAR_T
572
template class time_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t> > >;
573
template class time_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t> > >;
574
#  endif
575
576
#endif
577
578
_STLP_END_NAMESPACE