Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
time_put.cpp
Go to the documentation of this file.
1
29#define _RWSTD_LIB_SRC
30#include <rw/_defs.h>
31
32// disable Compaq C++ pure C headers
33#undef __PURE_CNAME
34
35#if (defined (__sun__) || defined (__sun) || defined (sun)) && defined (__EDG__)
36 // get tzset() from <time.h>
37# define _XOPEN_SOURCE
38#endif
39
40#ifdef __CYGWIN__
41 // force CygWin <time.h> to define timezone as an int variable,
42 // not as a void function returning char*
43# define timezonevar
44#endif // __CYGWIN__
45
46
47#include <ctype.h> // for isspace(), ...
48#include <stdio.h> // for sprintf()
49#include <stddef.h> // for offsetof()
50#include <stdlib.h> // for getenv()
51#include <string.h> // for memcpy(), strlen()
52#include <time.h> // for strftime(), struct tm, tzset()
53#include <wchar.h> // for wcsftime()
54
55#ifndef _MSC_VER
56
57# ifndef _RWSTD_NO_PURE_C_HEADERS
58# include <locale.h>
59# ifndef LC_MESSAGES
60# define LC_MESSAGES _RWSTD_LC_MESSAGES
61# endif // LC_MESSAGES
62# endif // _RWSTD_NO_PURE_C_HEADERS
63
64# ifndef _RWSTD_NO_NL_LANGINFO
65# include <langinfo.h> // for nl_langinfo()
66# endif
67#else // if defined (_MSC_VER)
68# if defined (_RWSTD_MSVC) && defined (_WIN64)
69 // shut up MSVC/Win64 complaints about possible loss of data
70# pragma warning (disable: 4244)
71# endif
72#endif // _MSC_VER
73
74#include "access.h"
75
76#include <loc/_ctype.h>
77#include <loc/_localedef.h>
78#include <loc/_punct.h>
79#include <loc/_time_put.h>
80
81#include <rw/_traits.h>
82
83#include "setlocale.h"
84#include "strtol.h"
85
86
87#if defined (__EDG__) || !defined (_RWSTD_NO_PURE_C_HEADERS)
88# if defined (__linux__) || defined (__sun)
89
90extern "C" {
91
92// declare these for Linux glibc and SunOS
93extern int daylight;
94extern long int timezone;
95extern void tzset () _LIBC_THROWS ();
96
97} // extern "C"
98
99# endif // __linux__ || __sun
100#endif // __EDG__ || !_RWSTD_NO_PURE_C_HEADERS
101
102
103#ifdef _RWSTD_NO_DAYLIGHT
104 // the XSI POSIX extension, daylight, is not declared in <time.h>
105# define daylight 0
106#endif // _RWSTD_NO_DAYLIGHT
107
108
109#if defined (_RWSTD_NO_WCSFTIME) && !defined (_RWSTD_NO_WCSFTIME_IN_LIBC)
110# if defined _RWSTD_WCSFTIME_ARG3_T
111
112# undef _RWSTD_NO_WCSFTIME
113
114extern "C" {
115
116size_t wcsftime (wchar_t*, size_t, _RWSTD_WCSFTIME_ARG3_T, const struct tm*);
117
118}
119# endif // _RWSTD_WCSFTIME_ARG3_T
120#endif // _RWSTD_NO_WCSFTIME && !_RWSTD_NO_WCSFTIME_IN_LIBC
121
122
124
125
126typedef _STD::ctype_base::mask MaskT;
127extern const MaskT __rw_classic_tab [];
128
129#define ISALPHA(c) \
130 (_RW::__rw_classic_tab [(unsigned char)c] & _RW::__rw_alpha)
131
132#define ISDIGIT(c) \
133 (_RW::__rw_classic_tab [(unsigned char)c] & _RW::__rw_digit)
134
135
136_RWSTD_SIZE_T
137__rw_get_timepunct (const _RW::__rw_facet*, int,
138 const void*[], const _RWSTD_SIZE_T []);
139
140// also declared in _time_put.cc
141_RWSTD_EXPORT char*
142__rw_put_time (const __rw_facet*, char*, _RWSTD_SIZE_T,
143 _STD::ios_base&, char, const tm*,
144 char, char, int, int);
145
146
147#ifndef _RWSTD_NO_WCHAR_T
148
149// also declared in _time_put.cc
150_RWSTD_EXPORT wchar_t*
151__rw_put_time (const __rw_facet*, wchar_t*, _RWSTD_SIZE_T,
152 _STD::ios_base&, wchar_t, const tm*,
153 char, char, int, int);
154
155#endif // _RWSTD_NO_WCHAR_T
156
157
158
161#ifdef _RWSTD_NO_NL_LANGINFO
162
163typedef unsigned char UChar;
164
165// compute the format string corresponding to the "%x" format specifier
166// in the current locale (set by setlocale (LC_ALL, ...))
167static _RWSTD_SIZE_T
168__rw_get_date_fmat (char *fmt)
169{
170 tm t;
171
172 memset (&t, 0, sizeof t);
173
174 // set a date consisting of unique components
175 // such as 2/1/1933
176 t.tm_mday = 1; t.tm_mon = 1; t.tm_year = 33;
177
178 char tmp [256];
179
180 tmp [0] = '\0';
181
182 // shut up gcc 2.9x warning: `%x' yields only last 2 digits of year
183 const char percent_x[] = "%x";
184 strftime (tmp, sizeof tmp, percent_x, &t);
185
186 char *pfmt = fmt;
187
188 char abday [256]; // buffer for abbreviated day name
189 char day [256]; // buffer for full day name
190 char abmon [256]; // buffer for abbreviated month name
191 char mon [256]; // buffer for full month name
192
193 _RWSTD_SIZE_T abday_len = 0;
194 _RWSTD_SIZE_T day_len;
195 _RWSTD_SIZE_T abmon_len;
196 _RWSTD_SIZE_T mon_len;
197
198 for (char *ptmp = tmp; *ptmp; ) {
199
200 // store all whitespace as part of format
201 for (; (isspace)(UChar (*ptmp)); ++ptmp)
202 *pfmt++ = *ptmp;
203
204 const char *begin = ptmp;
205
206 // skip over all non-digit characters
207 for (; *ptmp && !(isdigit)(UChar (*ptmp)); ++ptmp) {
208 if ((ispunct)(UChar (*ptmp)) || (isspace)(UChar (*ptmp))) {
209 // store all punctuators as part of format
210 for ( ; (ispunct)(UChar (*ptmp)) || (isspace)(UChar (*ptmp)); ++ptmp)
211 *pfmt++ = *ptmp;
212 break;
213 }
214 else
215 *pfmt++ = *ptmp;
216 }
217
218 const _RWSTD_SIZE_T len = ptmp - begin;
219
220 if (len > 1) {
221
222 // if there are 2 or more characters in this date component
223 // try to match the sequence against one of the names
224
225 if (!abday_len) {
226 // initialize day and month names only when necessary
227 abday_len = strftime (abday, sizeof abday, "%a", &t);
228 day_len = strftime (day, sizeof day, "%A", &t);
229 abmon_len = strftime (abmon, sizeof abmon, "%b", &t);
230 mon_len = strftime (mon, sizeof mon, "%B", &t);
231 }
232
233 char fmtchar = '\0';
234 _RWSTD_SIZE_T start = 0;
235
236 if (day_len <= len && !memcmp (day, begin, day_len)) {
237 fmtchar = 'A';
238 start = day_len;
239 }
240 else if (mon_len <= len && !memcmp (mon, begin, mon_len)) {
241 fmtchar = 'B';
242 start = mon_len;
243 }
244 else if (abday_len <= len && !memcmp (abday, begin, abday_len)) {
245 fmtchar = 'a';
246 start = abday_len;
247 }
248 else if (abmon_len <= len && !memcmp (abmon, begin, abmon_len)) {
249 fmtchar = 'b';
250 start = abmon_len;
251 }
252
253 if (fmtchar) {
254 pfmt -= len;
255 *pfmt++ = '%';
256 *pfmt++ = fmtchar;
257 for (; start != len; ++start)
258 *pfmt++ = begin [start];
259 }
260 }
261
262 if ((isdigit)(UChar (*ptmp))) {
263
264 for (begin = ptmp; (isdigit)(UChar (*ptmp)); ++ptmp);
265
266 *pfmt++ = '%';
267 if (ptmp - begin == 1) {
268 if ('1' == *begin) {
269 if (pfmt != fmt + 1 && ' ' == pfmt [-2]) {
270 pfmt [-2] = '%';
271 --pfmt;
272 }
273 *pfmt++ = 'e';
274 }
275 else if ('2' == *begin) {
276 *pfmt++ = 'm';
277 }
278 }
279 else if (ptmp - begin == 2) {
280 if ('0' == begin [0] && '1' == begin [1])
281 *pfmt++ = 'd';
282 else if ('0' == begin [0] && '2' == begin [1])
283 *pfmt++ = 'm';
284 else if ('3' == begin [0] && '3' == begin [1])
285 *pfmt++ = 'y';
286 else
287 *pfmt++ = '*';
288 }
289 else if (ptmp - begin == 4 && !memcmp (begin, "1933", 4))
290 *pfmt++ = 'Y';
291 else
292 *pfmt++ = '*';
293 }
294 }
295
296 *pfmt++ = '\0';
297
298 return pfmt - fmt;
299}
300
301
302// compute the format string corresponding to the "%X" format specifier
303// in the current locale (set by setlocale (LC_ALL, ...))
304static _RWSTD_SIZE_T
305__rw_get_time_fmat (char *fmt)
306{
307 tm t;
308
309 memset (&t, 0, sizeof t);
310
311 t.tm_sec = 3; t.tm_min = 4; t.tm_hour = 21; // "9 PM" or "21"
312
313 char tmp [256];
314
315 tmp [0] = '\0';
316 strftime (tmp, sizeof tmp, "%X", &t);
317
318 char *pfmt = fmt;
319
320 char pm [256]; // buffer for pm designator
321
322 _RWSTD_SIZE_T pm_len = 0;
323
324 for (char *ptmp = tmp; *ptmp; ) {
325
326 for (; (isspace)(UChar (*ptmp)); ++ptmp)
327 *pfmt++ = *ptmp;
328
329 const char *begin = ptmp;
330
331 for (; *ptmp && !(isdigit)(UChar (*ptmp)); ++ptmp) {
332 if ( (ispunct)(UChar (*ptmp))
333 || (isspace)(UChar (*ptmp))) {
334 for (; (ispunct)(UChar (*ptmp))
335 || (isspace)(UChar (*ptmp)); ++ptmp)
336 *pfmt++ = *ptmp;
337 break;
338 }
339 else
340 *pfmt++ = *ptmp;
341 }
342
343 const _RWSTD_SIZE_T len = ptmp - begin;
344
345 if (len > 1) {
346 if (0 == pm_len) {
347 strftime (pm, sizeof pm, "%p", &t);
348 pm_len = strlen (pm);
349 }
350
351 if ( pm_len <= len
352 && !::memcmp (pm, begin, pm_len)) {
353 pfmt -= len;
354 *pfmt++ = '%';
355 *pfmt++ = 'p';
356
357 // copy whatever follows the pm designator
358 for (_RWSTD_SIZE_T i = pm_len; i != len; ++i)
359 *pfmt++ = begin [i];
360 }
361 }
362
363 if ((isdigit)(UChar (*ptmp))) {
364
365 for (begin = ptmp; (isdigit)(UChar (*ptmp)); ++ptmp);
366
367 *pfmt++ = '%';
368
369 if (pfmt != fmt + 1 && ' ' == pfmt [-2]) {
370 pfmt [-2] = '%';
371 --pfmt;
372 }
373
374 if (ptmp - begin == 1) {
375
376 switch (*begin) {
377 case '3': *pfmt++ = 'S'; break; // tm_sec
378 case '4': *pfmt++ = 'M'; break; // tm_min
379 case '9': *pfmt++ = 'I'; break; // tm_hour
380 default: *pfmt++ = '\0';
381 }
382 }
383 else if (ptmp - begin == 2) {
384
385 if ('0' == begin [0]) {
386 switch (begin [1]) {
387 case '3': *pfmt++ = 'S'; break; // tm_sec
388 case '4': *pfmt++ = 'M'; break; // tm_min
389 case '9': *pfmt++ = 'I'; break; // tm_hour
390 default: *pfmt++ = '\0';
391 }
392 }
393 else if ('2' == begin [0] && '1' == begin [1]) {
394 *pfmt++ = 'H';
395 }
396 else
397 *pfmt++ = '\0';
398 }
399 else
400 *pfmt++ = '\0';
401 }
402 }
403
404 *pfmt++ = '\0';
405
406 return pfmt - fmt;
407}
408
409
410#endif // _RWSTD_NO_NL_LANGINFO
411
412
413const void*
414__rw_get_timepunct (const __rw_facet *pfacet, int flags, _RWSTD_SIZE_T inx)
415{
416 const int member = flags & ~__rw_wide;
417 const bool wide = !!(flags & __rw_wide);
418
419 const void *pdata = pfacet->_C_data ();
420
421 if (pdata) {
422
423 const __rw_time_t* const pun =
424 _RWSTD_STATIC_CAST (const __rw_time_t*, pdata);
425
426 switch (member) {
427 case __rw_abday: return pun->abday (inx, wide);
428 case __rw_day: return pun->day (inx, wide);
429 case __rw_abmon: return pun->abmon (inx, wide);
430 case __rw_month: return pun->mon (inx, wide);
431 case __rw_ampm: return pun->am_pm (inx, wide);
432 case __rw_d_t_fmt: return pun->d_t_fmt (wide);
433 case __rw_d_fmt: return pun->d_fmt (wide);
434 case __rw_t_fmt: return pun->t_fmt (wide);
435 case __rw_t_fmt_ampm: return pun->t_fmt_ampm (wide);
436 case __rw_era_d_t_fmt: return pun->era_d_t_fmt (wide);
437 case __rw_era_d_fmt: return pun->era_d_fmt (wide);
438 case __rw_era_t_fmt: return pun->era_t_fmt (wide);
439 case __rw_era_names: return pun->era_name (inx, wide);
440 case __rw_era_fmts: return pun->era_fmt (inx, wide);
441 case __rw_alt_digits: return pun->alt_digits (inx, wide);
442
443 default: return pdata;
444 }
445 }
446
447 const char* const locname = pfacet->_C_get_name ();
448
449 // set all categories (need LC_TIME and LC_CTYPE) and lock
450 const __rw_setlocale clocale (locname, _RWSTD_LC_ALL);
451
452 _RWSTD_SIZE_T bufsize = 2048;
453
454 const size_t newsize = bufsize + sizeof (__rw_time_t);
455
456 // allocate memory using operator new to avoid mismatch with
457 // facet destructor
458 char *pbuf = _RWSTD_STATIC_CAST (char*, ::operator new (newsize));
459
460 __rw_time_t *pun = _RWSTD_REINTERPRET_CAST (__rw_time_t*, pbuf);
461
462 // zero out all members
463 memset (pun, 0, sizeof *pun);
464
465 // advance buffer pointer past the end of the structure
466 pbuf += sizeof *pun;
467
468#ifndef _RWSTD_NO_WCHAR_T
469
470 // reserve offset 0 for the empty string (both narrow and wide)
471 *_RWSTD_REINTERPRET_CAST (wchar_t*, pbuf) = L'\0';
472
473 _RWSTD_SIZE_T off = sizeof (wchar_t);
474
475#else // if defined (_RWSTD_NO_WCHAR_T)
476
477 // reserve offset 0 for the empty string
478 *pbuf = '\0';
479
480 _RWSTD_SIZE_T off = sizeof (char);
481
482#endif // _RWSTD_NO_WCHAR_T
483
484#ifndef _RWSTD_NO_NL_LANGINFO
485
486 static const struct {
487 int nl_item; // argument to nl_langinfo()
488 _RWSTD_SIZE_T moff [2]; // member offset
489 } nl_items [] = {
490
491
492#ifndef _RWSTD_NO_OFFSETOF
493# define OFF(T, m) offsetof (T, m)
494#else
495# define OFF(T, m) ((char*)&((T*)0)->m - (char*)0)
496#endif // _RWSTD_NO_OFFSETOF
497
498
499#undef ENTRY
500#define ENTRY(item, mem1, mem2) { \
501 item, \
502 { OFF (__rw_time_t, __rw_time_t::mem1) / sizeof (_RWSTD_UINT32_T), \
503 OFF (__rw_time_t, __rw_time_t::mem2) / sizeof (_RWSTD_UINT32_T) } \
504 }
505
506 // each entry contains an `nl_item' value followed by the offset
507 // of __rw_time_t member; offsets rather than addresses are used
508 // to allow the __rw_time_t struct to be reallocated w/o having
509 // to reinitialize the array; this also allows the array to be
510 // static const for further speed improvement
511 ENTRY (D_T_FMT, d_t_fmt_off [0], d_t_fmt_off [1]),
512 ENTRY (D_FMT, d_fmt_off [0], d_fmt_off [1]),
513 ENTRY (T_FMT, t_fmt_off [0], t_fmt_off [1]),
514
515#ifdef T_FMT_AMPM
516 ENTRY (T_FMT_AMPM, t_fmt_ampm_off [0], t_fmt_ampm_off [1]),
517#else
518 ENTRY (D_T_FMT, t_fmt_ampm_off [0], t_fmt_ampm_off [1]),
519#endif // T_FMT_AMPM
520
521 ENTRY (AM_STR, am_pm_off [0][0], am_pm_off [1][0]),
522 ENTRY (PM_STR, am_pm_off [0][1], am_pm_off [1][1]),
523
524 ENTRY (ABDAY_1, abday_off [0][0], abday_off [1][0]),
525 ENTRY (ABDAY_2, abday_off [0][1], abday_off [1][1]),
526 ENTRY (ABDAY_3, abday_off [0][2], abday_off [1][2]),
527 ENTRY (ABDAY_4, abday_off [0][3], abday_off [1][3]),
528 ENTRY (ABDAY_5, abday_off [0][4], abday_off [1][4]),
529 ENTRY (ABDAY_6, abday_off [0][5], abday_off [1][5]),
530 ENTRY (ABDAY_7, abday_off [0][6], abday_off [1][6]),
531
532 ENTRY (DAY_1, day_off [0][0], day_off [1][0]),
533 ENTRY (DAY_2, day_off [0][1], day_off [1][1]),
534 ENTRY (DAY_3, day_off [0][2], day_off [1][2]),
535 ENTRY (DAY_4, day_off [0][3], day_off [1][3]),
536 ENTRY (DAY_5, day_off [0][4], day_off [1][4]),
537 ENTRY (DAY_6, day_off [0][5], day_off [1][5]),
538 ENTRY (DAY_7, day_off [0][6], day_off [1][6]),
539
540 ENTRY (ABMON_1, abmon_off [0][ 0], abmon_off [1][ 0]),
541 ENTRY (ABMON_2, abmon_off [0][ 1], abmon_off [1][ 1]),
542 ENTRY (ABMON_3, abmon_off [0][ 2], abmon_off [1][ 2]),
543 ENTRY (ABMON_4, abmon_off [0][ 3], abmon_off [1][ 3]),
544 ENTRY (ABMON_5, abmon_off [0][ 4], abmon_off [1][ 4]),
545 ENTRY (ABMON_6, abmon_off [0][ 5], abmon_off [1][ 5]),
546 ENTRY (ABMON_7, abmon_off [0][ 6], abmon_off [1][ 6]),
547 ENTRY (ABMON_8, abmon_off [0][ 7], abmon_off [1][ 7]),
548 ENTRY (ABMON_9, abmon_off [0][ 8], abmon_off [1][ 8]),
549 ENTRY (ABMON_10, abmon_off [0][ 9], abmon_off [1][ 9]),
550 ENTRY (ABMON_11, abmon_off [0][10], abmon_off [1][10]),
551 ENTRY (ABMON_12, abmon_off [0][11], abmon_off [1][11]),
552
553 ENTRY (MON_1, mon_off [0][ 0], mon_off [1][ 0]),
554 ENTRY (MON_2, mon_off [0][ 1], mon_off [1][ 1]),
555 ENTRY (MON_3, mon_off [0][ 2], mon_off [1][ 2]),
556 ENTRY (MON_4, mon_off [0][ 3], mon_off [1][ 3]),
557 ENTRY (MON_5, mon_off [0][ 4], mon_off [1][ 4]),
558 ENTRY (MON_6, mon_off [0][ 5], mon_off [1][ 5]),
559 ENTRY (MON_7, mon_off [0][ 6], mon_off [1][ 6]),
560 ENTRY (MON_8, mon_off [0][ 7], mon_off [1][ 7]),
561 ENTRY (MON_9, mon_off [0][ 8], mon_off [1][ 8]),
562 ENTRY (MON_10, mon_off [0][ 9], mon_off [1][ 9]),
563 ENTRY (MON_11, mon_off [0][10], mon_off [1][10]),
564 ENTRY (MON_12, mon_off [0][11], mon_off [1][11]),
565
566#ifdef ERA_D_T_FMT
567 ENTRY (ERA_D_T_FMT, era_d_t_fmt_off [0], era_d_t_fmt_off [1]),
568#else
569 ENTRY (D_T_FMT, era_d_t_fmt_off [0], era_d_t_fmt_off [1]),
570#endif // ERA_D_T_FMT
571
572#ifdef ERA_D_FMT
573 ENTRY (ERA_D_FMT, era_d_fmt_off [0], era_d_fmt_off [1]),
574#else
575 ENTRY (D_T_FMT, era_d_fmt_off [0], era_d_fmt_off [1]),
576#endif // ERA_D_FMT
577
578#ifdef ERA_T_FMT
579 ENTRY (ERA_T_FMT, era_t_fmt_off [0], era_t_fmt_off [1])
580#else
581 ENTRY (D_T_FMT, era_t_fmt_off [0], era_t_fmt_off [1])
582#endif // ERA_T_FMT
583
584 };
585
586 // points to the first __rw_time_t data member
587 _RWSTD_UINT32_T *pmem = _RWSTD_REINTERPRET_CAST (_RWSTD_UINT32_T*, pun);
588
589 const bool c_locale = 'C' == locname [0] && '\0' == locname [1];
590
591 for (_RWSTD_SIZE_T i = 0; i != sizeof nl_items / sizeof *nl_items; ++i) {
592
593 if (D_T_FMT == nl_items [i].nl_item && i)
594 continue;
595
596 // enforce POSIX rules for "%c" in the "C" locale
597 const char* const str = i || !c_locale ?
598 nl_langinfo (nl_items [i].nl_item) : "%a %b %e %H:%M:%S %Y";
599
600 _RWSTD_ASSERT (0 != str);
601
602 _RWSTD_SIZE_T size = 1 + strlen (str);
603
604 // estimate the size required to accommodate both
605 // the narrow and the wide char representations
606 const _RWSTD_SIZE_T estsize = size * (1 + sizeof (wchar_t));
607
608 if (off + estsize >= bufsize) {
609 // reallocate
610 const size_t tmpsize = sizeof *pun + bufsize * 2 + estsize;
611
612 // reallocate, again using operator new to avoid mismatch
613 // with facet destructor
614 char* const tmp =
615 _RWSTD_STATIC_CAST(char*, ::operator new (tmpsize));
616 memcpy (tmp, pun, sizeof *pun + off);
617
618 ::operator delete (pun);
619
620 pun = _RWSTD_REINTERPRET_CAST (__rw_time_t*, tmp);
621 pmem = _RWSTD_REINTERPRET_CAST (_RWSTD_UINT32_T*, pun);
622 pbuf = tmp + sizeof *pun;
623 bufsize = bufsize * 2 + estsize;
624 }
625
626 // copy string to the allocated buffer and set its offset
627 memcpy (pbuf + off, str, size);
628 pmem [nl_items [i].moff [0]] =
629 _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
630 off += size;
631
632#ifndef _RWSTD_NO_WCHAR_T
633
634 // make sure wide string is properly aligned
635 const _RWSTD_SIZE_T align = off % sizeof (wchar_t);
636 if (align)
637 off += sizeof (wchar_t) - align;
638
639 // widen the narrow (multibyte) string into the allocated buffer
640 // (at an appropriately aligned offset) and set its offset
641 wchar_t* const pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
642 size = mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
643
644 if (_RWSTD_SIZE_MAX == size) {
645 // conversion failure - should not happen
646 *pwbuf = L'\0';
647 size = 1;
648 }
649 else {
650 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
651 size += 1;
652 }
653
654 pmem [nl_items [i].moff [1]] =
655 _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
656 off += size * sizeof (wchar_t);
657
658#endif // _RWSTD_NO_WCHAR_T
659
660 }
661
662#else // if defined (_RWSTD_NO_NL_LANGINFO)
663
664 tm t;
665
666 memset (&t, 0, sizeof t);
667
668 _RWSTD_SIZE_T len;
669
670
671#if 0 // FIXME: implement same way as above
672
673 static const struct {
674 int tm:: *pmem;
675 _RWSTD_SIZE_T moff;
676 const char fmt [3];
677 int begin;
678 int end;
679 int step;
680 } fmats [] = {
681 { &tm::tm_wday, "%a", 0, 7, 1 },
682 { &tm::tm_wday, "%A", 0, 7, 1 },
683 { &tm::tm_mon, "%b", 0, 12, 1 },
684 { &tm::tm_mon, "%B", 0, 12, 1 },
685 { &tm::tm_hour, "%p", 1, 13, 12 }
686 };
687
688 for (_RWSTD_SIZE_T i = 0; i != sizeof fmats / sizef *fmats; ++i) {
689
690 for (int j = fmats [i].begin; j != fmats [i].end; j != fmats [i].step) {
691
692 t.*fmats [i].pmem = j;
693
694 len = strftime (pbuf + off, bufsize - off, fmats [i].fmt, &t);
695
696 pun->abday_off [0][t.tm_wday] = off;
697 off += len + 1;
698 }
699 }
700
701#endif // 0/1
702
703
704 // copy abbreaviated and full names of days
705 for (t.tm_wday = 0; t.tm_wday != 7; ++t.tm_wday) {
706
707 len = strftime (pbuf + off, bufsize - off, "%a", &t);
708
709 pun->abday_off [0][t.tm_wday] =
710 _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
711 off += len + 1;
712
713 len = strftime (pbuf + off, bufsize - off, "%A", &t);
714
715 pun->day_off [0][t.tm_wday] =
716 _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
717 off += len + 1;
718
719# ifndef _RWSTD_NO_WCHAR_T
720
721 // make sure wide strings are properly aligned
722 const _RWSTD_SIZE_T align = off % sizeof (wchar_t);
723 if (align)
724 off += sizeof (wchar_t) - align;
725
726# ifndef _RWSTD_NO_WCSFTIME
727
728 wchar_t *pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
729 len = wcsftime (pwbuf, (bufsize - off) / sizeof (*pwbuf), L"%a", &t);
730
731 pun->abday_off [1][t.tm_wday] =
732 _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
733 off += (len + 1) * sizeof (wchar_t);
734
735 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
736 len = wcsftime (pwbuf, (bufsize - off) / sizeof (*pwbuf), L"%A", &t);
737
738 pun->day_off [1][t.tm_wday] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
739 off += (len + 1) * sizeof (wchar_t);
740
741# else // if defined (_RWSTD_NO_WCSFTIME)
742
743 // widen the narrow (multibyte) string into the allocated buffer
744 // (at an appropriately aligned offset) and set its offset
745 const char *str =
746 _RWSTD_STATIC_CAST (const char*, pun->abday (t.tm_wday, 0));
747
748 wchar_t *pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
749 _RWSTD_SIZE_T size =
750 mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
751
752 if (_RWSTD_SIZE_MAX == size) {
753 // conversion failure - should not happen
754 *pwbuf = L'\0';
755 size = 1;
756 }
757 else {
758 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
759 size += 1;
760 }
761
762 pun->abday_off [1][t.tm_wday] = off;
763 off += size * sizeof (wchar_t);
764
765 str = _RWSTD_STATIC_CAST (const char*, pun->day (t.tm_wday, 0));
766 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
767 size = mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
768
769 if (_RWSTD_SIZE_MAX == size) {
770 // conversion failure - should not happen
771 *pwbuf = L'\0';
772 size = 1;
773 }
774 else {
775 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
776 size += 1;
777 }
778
779 pun->day_off [1][t.tm_wday] = off;
780 off += size * sizeof (wchar_t);
781
782# endif // _RWSTD_NO_WCSFTIME
783# endif // _RWSTD_NO_WCHAR_T
784
785 }
786
787 // copy abbreaviated and full names of months
788 for (t.tm_mon = 0; t.tm_mon != 12; ++t.tm_mon) {
789
790 len = strftime (pbuf + off, bufsize - off, "%b", &t);
791
792 pun->abmon_off [0][t.tm_mon] =
793 _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
794 off += len + 1;
795
796 len = strftime (pbuf + off, bufsize - off, "%B", &t);
797
798 pun->mon_off [0][t.tm_mon] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
799 off += len + 1;
800
801# ifndef _RWSTD_NO_WCHAR_T
802
803 // make sure wide strings are properly aligned
804 const _RWSTD_SIZE_T align = off % sizeof (wchar_t);
805 if (align)
806 off += sizeof (wchar_t) - align;
807
808# ifndef _RWSTD_NO_WCSFTIME
809
810 wchar_t *pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
811 len = wcsftime (pwbuf, (bufsize - off) / sizeof (*pwbuf), L"%b", &t);
812
813 pun->abmon_off [1][t.tm_mon] =
814 _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
815 off += (len + 1) * sizeof (wchar_t);
816
817 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
818 len = wcsftime (pwbuf, (bufsize - off) / sizeof (*pwbuf), L"%B", &t);
819
820 pun->mon_off [1][t.tm_mon] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
821 off += (len + 1) * sizeof (wchar_t);
822
823# else // if defined (_RWSTD_NO_WCSFTIME)
824
825 // widen the narrow (multibyte) string into the allocated buffer
826 // (at an appropriately aligned offset) and set its offset
827 const char *str =
828 _RWSTD_STATIC_CAST (const char*, pun->abmon (t.tm_mon, 0));
829 wchar_t *pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
830 _RWSTD_SIZE_T size =
831 mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
832
833 if (_RWSTD_SIZE_MAX == size) {
834 // conversion failure - should not happen
835 *pwbuf = L'\0';
836 size = 1;
837 }
838 else {
839 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
840 size += 1;
841 }
842
843 pun->abmon_off [1][t.tm_mon] = off;
844 off += size * sizeof (wchar_t);
845
846 str = _RWSTD_STATIC_CAST (const char*, pun->mon (t.tm_mon, 0));
847 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
848 size = mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
849
850 if (_RWSTD_SIZE_MAX == size) {
851 // conversion failure - should not happen
852 *pwbuf = L'\0';
853 size = 1;
854 }
855 else {
856 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
857 size += 1;
858 }
859
860 pun->mon_off [1][t.tm_mon] = off;
861 off += size * sizeof (wchar_t);
862
863# endif // _RWSTD_NO_WCSFTIME
864# endif // _RWSTD_NO_WCHAR_T
865
866 }
867
868 // copy AM/PM designations
869 t.tm_hour = 1;
870 len = strftime (pbuf + off, bufsize - off, "%p", &t);
871 pun->am_pm_off [0][0] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
872 off += len + 1;
873
874 t.tm_hour = 13;
875 len = strftime (pbuf + off, bufsize - off, "%p", &t);
876 pun->am_pm_off [0][1] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
877 off += len + 1;
878
879 // determine the locale's "%x" format (date representation)
880 len = __rw_get_date_fmat (pbuf + off);
881 pun->d_fmt_off [0] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
882 off += len + 1;
883
884 // determine the locale's "%X" format (time representation)
885 len = __rw_get_time_fmat (pbuf + off);
886 pun->t_fmt_off [0] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
887 off += len + 1;
888
889 // FIXME: determine "%r" at runtime (just like "%x" and "%X")
890 // or have time_put use strftime() instead of hardcoding
891 // the default "POSIX" format
892
893 static const char t_fmt_ampm_fmat[] = "%I:%M:%S %p";
894
895 len = sizeof t_fmt_ampm_fmat;
896 memcpy (pbuf + off, t_fmt_ampm_fmat, len);
897 pun->t_fmt_ampm_off [0] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
898 off += len;
899
900 // FIXME: determine "%c" at runtime (just like "%x" and "%X"),
901 // or have time_put use strftime() instead of hardcoding
902 // the default "C" format
903
904 static const char d_t_fmat[] = "%a %b %e %H:%M:%S %Y";
905 len = sizeof d_t_fmat;
906 memcpy (pbuf + off, d_t_fmat, len);
907 pun->d_t_fmt_off [0] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
908 off += len;
909
910 // FIXME: determine "%Ec", "%EX", "%Ex"
911 pbuf [off] = '\0';
912 pun->era_d_t_fmt_off [0] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
913 pun->era_d_fmt_off [0] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
914 pun->era_t_fmt_off [0] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
915 off += 1;
916
917# ifndef _RWSTD_NO_WCHAR_T
918
919 const _RWSTD_SIZE_T align = off % sizeof (wchar_t);
920 if (align)
921 off += sizeof (wchar_t) - align;
922
923 const char *str;
924 wchar_t *pwbuf;
925 _RWSTD_SIZE_T size;
926
927# ifndef _RWSTD_NO_WCSFTIME
928
929 t.tm_hour = 1;
930 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
931 len = wcsftime (pwbuf, (bufsize - off) / sizeof (*pwbuf), L"%p", &t);
932 pun->am_pm_off [1][0] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
933 off += (len + 1) * sizeof (wchar_t);
934
935 t.tm_hour = 13;
936 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
937 len = wcsftime (pwbuf, (bufsize - off) / sizeof (*pwbuf), L"%p", &t);
938 pun->am_pm_off [1][1] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
939 off += (len + 1) * sizeof (wchar_t);
940
941# else // if defined (_RWSTD_NO_WCSFTIME)
942
943 str = _RWSTD_STATIC_CAST (const char*, pun->am_pm (0, 0));
944 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
945 size = mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
946
947 if (_RWSTD_SIZE_MAX == size) {
948 // conversion failure - should not happen
949 *pwbuf = L'\0';
950 size = 1;
951 }
952 else {
953 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
954 size += 1;
955 }
956
957 pun->am_pm_off [1][0] = off;
958 off += size * sizeof (wchar_t);
959
960 str = _RWSTD_STATIC_CAST (const char*, pun->am_pm (1, 0));
961 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
962 size = mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
963
964 if (_RWSTD_SIZE_MAX == size) {
965 // conversion failure - should not happen
966 *pwbuf = L'\0';
967 size = 1;
968 }
969 else {
970 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
971 size += 1;
972 }
973
974 pun->am_pm_off [1][1] = off;
975 off += size * sizeof (wchar_t);
976
977# endif // _RWSTD_NO_WCSFTIME
978
979 // convert "%x" to its wide equivalent
980 str = _RWSTD_STATIC_CAST (const char*, pun->d_fmt (0));
981 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
982 size = mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
983
984 if (_RWSTD_SIZE_MAX == size) {
985 // conversion failure - should not happen
986 *pwbuf = L'\0';
987 size = 1;
988 }
989 else {
990 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
991 size += 1;
992 }
993
994 pun->d_fmt_off [1] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
995 off += size * sizeof (wchar_t);
996
997 // convert "%X" to its wide equivalent
998 str = _RWSTD_STATIC_CAST (const char*, pun->t_fmt (0));
999 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
1000 size = mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
1001
1002 if (_RWSTD_SIZE_MAX == size) {
1003 // conversion failure - should not happen
1004 *pwbuf = L'\0';
1005 size = 1;
1006 }
1007 else {
1008 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
1009 size += 1;
1010 }
1011
1012 pun->t_fmt_off [1] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
1013 off += size * sizeof (wchar_t);
1014
1015 // convert "%c" to its wide equivalent
1016 str = _RWSTD_STATIC_CAST (const char*, pun->d_t_fmt (0));
1017 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
1018 size = mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
1019
1020 if (_RWSTD_SIZE_MAX == size) {
1021 // conversion failure - should not happen
1022 *pwbuf = L'\0';
1023 size = 1;
1024 }
1025 else {
1026 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
1027 size += 1;
1028 }
1029
1030 pun->d_t_fmt_off [1] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
1031 off += size * sizeof (wchar_t);
1032
1033 // convert "%r" to its wide equivalent
1034 str = _RWSTD_STATIC_CAST (const char*, pun->t_fmt_ampm (0));
1035 pwbuf = _RWSTD_REINTERPRET_CAST (wchar_t*, pbuf + off);
1036 size = mbstowcs (pwbuf, str, (bufsize - off) / sizeof (*pwbuf));
1037
1038 if (_RWSTD_SIZE_MAX == size) {
1039 // conversion failure - should not happen
1040 *pwbuf = L'\0';
1041 size = 1;
1042 }
1043 else {
1044 _RWSTD_ASSERT (L'\0' == pwbuf [size]);
1045 size += 1;
1046 }
1047
1048 pun->t_fmt_ampm_off [1] = _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, off);
1049 off += size * sizeof (wchar_t);
1050
1051# endif // _RWSTD_NO_WCHAR_T
1052#endif // _RWSTD_NO_NL_LANGINFO
1053
1054 // set `impdata' and `impsize' (base dtor will delete)
1055 __rw_access::_C_get_impdata (*_RWSTD_CONST_CAST (__rw_facet*, pfacet))
1056 = pun;
1057
1058 __rw_access::_C_get_impsize (*_RWSTD_CONST_CAST (__rw_facet*, pfacet))
1059 = _RWSTD_SIZE_MAX;
1060
1061 // call self recursively on already initialized `impdata'
1062 return __rw_get_timepunct (pfacet, flags, inx);
1063}
1064
1065
1066_RWSTD_SIZE_T
1067__rw_get_timepunct (const __rw_facet *pfacet, int flags,
1068 const void *names[], _RWSTD_SIZE_T sizes[])
1069{
1070 const bool wide = !!(flags & __rw_wide);
1071
1072 const int member = flags & ~__rw_wide;
1073
1074 _RWSTD_SIZE_T count = 0;
1075
1076 int flags_2 = 0;
1077
1078 switch (member) {
1079 case __rw_abday:
1080 case __rw_day:
1081 count = 7;
1082 break;
1083
1084 case __rw_abmon:
1085 case __rw_month:
1086 count = 12;
1087 break;
1088
1089 case __rw_ampm:
1090 count = 2;
1091 break;
1092
1093 case __rw_d_t_fmt:
1094 case __rw_d_fmt:
1095 case __rw_t_fmt:
1096 case __rw_t_fmt_ampm:
1097 case __rw_era_d_t_fmt:
1098 case __rw_era_d_fmt:
1099 case __rw_era_t_fmt:
1100 count = 1;
1101 break;
1102
1103 case __rw_era_fmts:
1104 case __rw_era_names: {
1105
1106 const __rw_time_t* const ptime =
1107 _RWSTD_STATIC_CAST (const __rw_time_t*,
1108 __rw_get_timepunct (pfacet, 0, 0));
1109
1110 count = (_RWSTD_SIZE_T)ptime->era_count ();
1111 break;
1112 }
1113
1114 case __rw_abday | __rw_day:
1115 count = 7;
1116 flags = __rw_day;
1117 flags_2 = __rw_abday;
1118 break;
1119
1120 case __rw_abmon | __rw_month:
1121 count = 12;
1122 flags = __rw_month;
1123 flags_2 = __rw_abmon;
1124 break;
1125
1126 case __rw_alt_digits: {
1127
1128 const __rw_time_t* const ptime =
1129 _RWSTD_STATIC_CAST (const __rw_time_t*,
1130 __rw_get_timepunct (pfacet, 0, 0));
1131
1132 count = (_RWSTD_SIZE_T)ptime->alt_digits_count ();
1133 break;
1134 }
1135
1136 default:
1137 _RWSTD_ASSERT (!"bad discriminant");
1138 return 0;
1139 }
1140
1141 typedef _STD::char_traits<char> CTraits;
1142
1143#ifndef _RWSTD_NO_WCHAR_T
1144
1145 typedef _STD::char_traits<wchar_t> WTraits;
1146
1147#endif // _RWSTD_NO_WCHAR_T
1148
1149 if (wide)
1150 flags |= __rw_wide;
1151
1152 for (_RWSTD_SIZE_T i = 0; i != count; ++i) {
1153 names [i] = __rw_get_timepunct (pfacet, flags, i);
1154
1155#ifndef _RWSTD_NO_WCHAR_T
1156
1157 if (wide)
1158 sizes [i] = WTraits::length ((const wchar_t*)names [i]);
1159 else
1160
1161#endif // _RWSTD_NO_WCHAR_T
1162
1163 sizes [i] = CTraits::length ((const char*)names [i]);
1164 }
1165
1166 if (flags_2) {
1167
1168 if (wide)
1169 flags_2 |= __rw_wide;
1170
1171 for (_RWSTD_SIZE_T j = count; j != 2 * count; ++j) {
1172 names [j] = __rw_get_timepunct (pfacet, flags_2, j - count);
1173
1174#ifndef _RWSTD_NO_WCHAR_T
1175
1176 if (wide)
1177 sizes [j] = WTraits::length ((const wchar_t*)names [j]);
1178 else
1179
1180#endif // _RWSTD_NO_WCHAR_T
1181
1182 sizes [j] = CTraits::length ((const char*)names [j]);
1183 }
1184
1185 return 2 * count;
1186 }
1187
1188 return count;
1189}
1190
1191
1192_RWSTD_EXPORT _RWSTD_SIZE_T
1193__rw_get_timepunct (const __rw_facet *pfacet,
1194 int data [4], tm *tmb, int **pmem,
1195 const void *names[], _RWSTD_SIZE_T sizes[])
1196{
1197 enum _Fmt { // for convenience
1198 _AmPm = __rw_ampm,
1199 _Date = __rw_d_fmt,
1200 _DateTime = __rw_d_t_fmt,
1201 _Days = __rw_day | __rw_abday,
1202 _Mons = __rw_month | __rw_abmon,
1203 _Time = __rw_t_fmt,
1204 _TimeAmPm = __rw_t_fmt_ampm,
1205
1206 // alternative formats and eras
1207 _AltDigits = __rw_alt_digits,
1208 _EraDate = __rw_era_d_fmt,
1209 _EraDateTime = __rw_era_d_t_fmt,
1210 _EraFmts = __rw_era_fmts,
1211 _EraTime = __rw_era_t_fmt,
1212 _EraNames = __rw_era_names
1213 };
1214
1215 const char fmt = data [0]; // on input, get the format...
1216 const char mod = data [1]; // ...and modifier characters
1217 const bool wide = 0 != data [2]; // narrow or wide specialization?
1218
1219 int &adj = data [0]; // value to increment computed result by
1220 int &fac = data [1]; // value to multiply computed result by
1221 int &lob = data [2]; // lower bound on valid input value
1222 int &hib = data [3]; // higher bound on valid input value
1223
1224 adj = 0;
1225 fac = 1;
1226 lob = 0;
1227 hib = 0;
1228
1229 const void** pv =
1230 _RWSTD_REINTERPRET_CAST (const void**, names);
1231
1232 _RWSTD_SIZE_T cnt = 0;
1233
1234 int flags = 0;
1235
1236 if ('E' == mod) {
1237
1238 switch (fmt) {
1239
1240 case 'C':
1241 // %EC: the name of the period in alternative representation
1242 *pmem = &tmb->tm_year;
1243 flags = _EraNames;
1244 break;
1245
1246 case 'c':
1247 // %Ec: alternative date and time representation
1248 flags = _EraDateTime;
1249 break;
1250
1251 case 'X':
1252 // %EX: alternative time representation
1253 flags = _EraTime;
1254 break;
1255
1256 case 'x':
1257 // %Ex: alternative date representation
1258 flags = _EraDate;
1259 break;
1260
1261 case 'Y':
1262 // %EY: full alternative year representation
1263 flags = _EraFmts;
1264 break;
1265
1266 case 'y':
1267 // %Ey: offset from %EC (year only) in alternative representation
1268 // FIXME: implement
1269 break;
1270 }
1271 }
1272 else if ('O' == mod) {
1273
1274 flags = _AltDigits;
1275
1276 switch (fmt) {
1277 case 'd': case 'e':
1278 // %Od: day of the month using alternative numeric symbols
1279 // %Oe: equivalent to %Od
1280 *pmem = &tmb->tm_mday;
1281 lob = 1;
1282 hib = 31;
1283 break;
1284
1285 case 'H':
1286 // %OH: hour (24-hour clock) using alternative numeric symbols
1287 *pmem = &tmb->tm_hour;
1288 hib = 23;
1289 break;
1290
1291 case 'I':
1292 // %OI: hour (12-hour clock) using the alternative numeric symbols
1293 *pmem = &tmb->tm_hour;
1294 hib = 12;
1295 break;
1296
1297 case 'm':
1298 // %Om: month using alternative numeric symbols
1299 *pmem = &tmb->tm_mon;
1300 adj = -1;
1301 hib = 11;
1302 break;
1303
1304 case 'M':
1305 // %OM: minutes using alternative numeric symbols
1306 *pmem = &tmb->tm_min;
1307 hib = 59;
1308 break;
1309
1310 case 'S':
1311 // %OS seconds using alternative numeric symbols
1312 *pmem = &tmb->tm_sec;
1313 hib = 60;
1314 break;
1315
1316 case 'U':
1317 // %OU: Sunday-based week number of the year
1318 // using alternative numeric symbols
1319 // FIXME: implement
1320 hib = 52;
1321 break;
1322
1323 case 'W':
1324 // %OW: Monday-based week number of the year
1325 // using alternative numeric symbols
1326 // FIXME: implement
1327 hib = 52;
1328 break;
1329
1330 case 'w':
1331 // %Ow: Sunday-based weekday using alternative numeric symbols
1332 *pmem = &tmb->tm_wday;
1333 hib = 6;
1334 break;
1335
1336 case 'y':
1337 // %Oy: year (offset from %C) using alternative numeric symbols
1338 *pmem = &tmb->tm_year;
1339 hib = 99;
1340 break;
1341
1342 default:
1343 flags = 0;
1344 }
1345 }
1346 else {
1347
1348 switch (fmt) {
1349
1350 case 'A': case 'a': // weekday [00..11]
1351 *pmem = &tmb->tm_wday;
1352 hib = 6;
1353 flags = _Days;
1354 break;
1355
1356 case 'B': case 'b': case 'h': // month [00..11]
1357 *pmem = &tmb->tm_mon;
1358 hib = 11;
1359 flags = _Mons;
1360 break;
1361
1362 case 'C': // century [00..99]
1363 adj = -1900;
1364 fac = 100;
1365 lob = -1900;
1366 hib = 8000;
1367 *pmem = &tmb->tm_year;
1368 break;
1369
1370 case 'c': // locale-specific date
1371 flags = _DateTime;
1372 break;
1373
1374 case 'D': { // equivalent to "%m/%d/%y"
1375 static const void* const pat[] = { "%m/%d/%y", L"%m/%d/%y" };
1376 names [0] = pat [wide];
1377 sizes [0] = 8;
1378 cnt = 1;
1379 break;
1380 }
1381
1382 case 'd': case 'e': // day of month [01..31]
1383 lob = 1;
1384 hib = 31;
1385 *pmem = &tmb->tm_mday;
1386 break;
1387
1388 case 'k': // popular extension (AIX, Linux, Solaris)
1389 case 'H': // hour [00..23]
1390 hib = 23;
1391 *pmem = &tmb->tm_hour;
1392 break;
1393
1394 case 'l': // popular extension (Linux, Solaris)
1395 case 'I': // hour [01..12]
1396 adj = -1;
1397 hib = 11;
1398 *pmem = &tmb->tm_hour;
1399 break;
1400
1401 case 'j': // day number of the year [001..366]
1402 adj = -1;
1403 hib = 365;
1404 *pmem = &tmb->tm_yday;
1405 break;
1406
1407 case 'M': // minutes [00..59]
1408 hib = 59;
1409 *pmem = &tmb->tm_min;
1410 break;
1411
1412 case 'm': // month [00..11]
1413 adj = -1;
1414 hib = 11;
1415 *pmem = &tmb->tm_mon;
1416 break;
1417
1418 case 'p': // the locale's equivalent of AM or PM
1419 *pmem = &tmb->tm_hour;
1420 flags = _AmPm;
1421 break;
1422
1423 case 'R': { // equivalent to "%H:%M"
1424 static const void* const pat[] = { "%H:%M", L"%H:%M" };
1425 names [0] = pat [wide];
1426 sizes [0] = 5;
1427 cnt = 1;
1428 break;
1429 }
1430
1431 case 'r': // 12-hour clock time using the AM/PM notation
1432 flags = _TimeAmPm;
1433 break;
1434
1435 case 'S': // seconds [00..60]
1436 hib = 60;
1437 *pmem = &tmb->tm_sec;
1438 break;
1439
1440 case 'T': { // equivalent to "%H:%M:%S"
1441 static const void* const pat[] = { "%H:%M:%S", L"%H:%M:%S" };
1442
1443 names [0] = pat [wide];
1444 sizes [0] = 8;
1445 cnt = 1;
1446 break;
1447 }
1448
1449 case 'U': // Sunday-based week number [00..53]
1450 hib = 53;
1451 // FIXME: implement
1452 break;
1453
1454 case 'W': // Monday-based week number [00..53]
1455 hib = 53;
1456 // FIXME: implement
1457 break;
1458
1459 case 'w': // Sunday-based weekday [0..6]
1460 hib = 6;
1461 *pmem = &tmb->tm_wday;
1462 break;
1463
1464 case 'x': // locale-specific date
1465 flags = _Date;
1466 break;
1467
1468 case 'X': // locale-specific time
1469 flags = _Time;
1470 break;
1471
1472 case 'y': // 2-digit year, [00..99]
1473 *pmem = &tmb->tm_year;
1474 break;
1475
1476 case 'Y': // 4-digit year
1477 adj = -1900;
1478 lob = -1900;
1479 hib = _RWSTD_INT_MAX - 1900;
1480 *pmem = &tmb->tm_year;
1481 break;
1482
1483 case '%':
1484 break;
1485 }
1486 }
1487
1488 if (flags)
1489 cnt = __rw_get_timepunct (pfacet, flags | (wide ? __rw_wide : 0),
1490 pv, sizes);
1491
1492 return cnt;
1493}
1494
1495
1496static char*
1497__rw_fmt_time (const __rw_facet *pfacet, char *buf, _RWSTD_SIZE_T bufsize,
1498 _STD::ios_base &flags, char fill, const tm *tmb,
1499 const char *pat)
1500{
1501 _RWSTD_ASSERT (0 != tmb);
1502 _RWSTD_ASSERT (0 != pat);
1503
1504 for (; *pat; ++pat) {
1505
1506 if ('%' == *pat && pat [1]) {
1507
1508 int width = -1; // width of curent specifier (-1 = unspecified)
1509 int prec = -1; // precision of current specifier
1510
1511 ++pat;
1512
1513 // Extension: width and precision
1514 // Reference: strftime() on HP-UX 11.00
1515 // Format: %[[-|0]w][.p]
1516
1517 // [-|0] right justification (left by default),
1518 // padded with '0' characters (spaces by default)
1519 // w minimum field width
1520 // .p minimum number of digits (expanded on the left with '0')
1521 // for the following specifiers:
1522 // d, H, I, j, m, M, o, S, U, w, W, y and Y
1523 // maximum number of characters (truncated if necessary)
1524 // for the following specifiers:
1525 // a, A, b, B, c, D, E, F, h, n, N, p, r, t,
1526 // T, x, X, z, Z, and %
1527
1528 if ('-' == *pat) {
1529 // right justify
1530 // FIXME: handle right justification
1531 ++pat;
1532 }
1533 else if ('0' == *pat) {
1534 // pad justified output with '0'
1535 fill = '0';
1536 ++pat;
1537 }
1538
1539 if (*pat >= '0' && *pat <= '9') {
1540
1541 // if width is given, set precision to 0 to prevent
1542 // it from being overridden later by __rw_put_time()
1543 width = 0;
1544 prec = 0;
1545
1546 for (; *pat >= '0' && *pat <= '9'; ++pat) {
1547 // set the width of the current specifier
1548 width = width * 10 + *pat - '0';
1549 }
1550 }
1551
1552 if ('.' == *pat) {
1553 ++pat;
1554
1555 if (*pat >= '0' && *pat <= '9') {
1556
1557 // treat missing width as 0 (e.g., "%.3d") to prevent
1558 // it from being overridden later by __rw_put_time()
1559 if (-1 == width)
1560 width = 0;
1561
1562 prec = 0;
1563
1564 for (; *pat >= '0' && *pat <= '9'; ++pat) {
1565 // set the precision of the current specifier
1566 prec = prec * 10 + *pat - '0';
1567 }
1568 }
1569 }
1570
1571 char fmtmod = *pat; // format modifier
1572 char fmt; // format specifier
1573
1574 if ('E' == fmtmod && *pat) {
1575
1576 fmt = *++pat;
1577
1578 switch (fmt) {
1579 // check valid format modifiers
1580 case 'c': case 'C': case 'x': case 'X': case 'y': case 'Y':
1581 break;
1582
1583 case '\0':
1584 break;
1585
1586 default:
1587 fmt = 0; // `pat' doesn't point to a valid format
1588 }
1589 }
1590 else if ('O' == fmtmod) {
1591
1592 fmt = *++pat;
1593
1594 switch (fmt) {
1595 // check valid format modifiers
1596 case 'd': case 'e': case 'H': case 'I': case 'm': case 'M':
1597 case 'S': case 'u': case 'U': case 'V': case 'w': case 'W':
1598 case 'y':
1599 break;
1600
1601 case '\0':
1602 break;
1603
1604 default:
1605 fmt = 0; // `pat' doesn't point to a valid format
1606 }
1607 }
1608 else {
1609 fmt = fmtmod;
1610 fmtmod = 0;
1611 }
1612
1613 if (char (-1) != fmt) {
1614 char *end = __rw_put_time (pfacet, buf, bufsize, flags, fill,
1615 tmb, fmt, fmtmod, width, prec);
1616
1617 if (!end)
1618 return 0;
1619
1620 buf = end;
1621 continue;
1622 }
1623 }
1624
1625 *buf++ = *pat;
1626 }
1627
1628 return buf;
1629}
1630
1631
1632#ifndef _RWSTD_NO_WCHAR_T
1633
1634static wchar_t*
1635__rw_fmt_time (const __rw_facet *pfacet, wchar_t *wbuf, _RWSTD_SIZE_T bufsize,
1636 _STD::ios_base &flags, wchar_t fill, const tm *tmb,
1637 const wchar_t *wpat)
1638{
1639 _RWSTD_ASSERT (0 != tmb);
1640 _RWSTD_ASSERT (0 != wpat);
1641
1642 for (; *wpat; ++wpat) {
1643
1644 if (L'%' == *wpat && wpat [1]) {
1645
1646 int width = -1; // width of the curent specifier (-1 = unspecified)
1647 int prec = -1; // precision of the current specifier
1648
1649 ++wpat;
1650
1651 // Extension: width and precision
1652 // Reference: strftime() on HP-UX 11.00
1653 // Format: %[[-|0]w][.p]
1654
1655 // [-|0] right justification (left by default),
1656 // padded with '0' characters (spaces by default)
1657 // w minimum field width
1658 // .p minimum number of digits (expanded on the left with '0')
1659 // for the following specifiers:
1660 // d, H, I, j, m, M, o, S, U, w, W, y and Y
1661 // maximum number of characters (truncated if necessary)
1662 // for the following specifiers:
1663 // a, A, b, B, c, D, E, F, h, n, N, p, r, t,
1664 // T, x, X, z, Z, and %
1665
1666 if (L'-' == *wpat) {
1667 // right justify
1668 // FIXME: handle right justification
1669 ++wpat;
1670 }
1671 else if (L'0' == *wpat) {
1672 // pad justified output with '0'
1673 fill = L'0';
1674 ++wpat;
1675 }
1676
1677 if (*wpat >= L'0' && *wpat <= L'9') {
1678
1679 // if width is given, set precision to 0 to prevent
1680 // it from being overridden later by __rw_put_time()
1681 width = 0;
1682 prec = 0;
1683
1684 for (; *wpat >= L'0' && *wpat <= L'9'; ++wpat) {
1685 // set the width of the current specifier
1686 width = width * 10U + *wpat - L'0';
1687 }
1688 }
1689
1690 if (L'.' == *wpat) {
1691 ++wpat;
1692
1693 if (*wpat >= L'0' && *wpat <= L'9') {
1694
1695 // treat missing width as 0 (e.g., "%.3d") to prevent
1696 // it from being overridden later by __rw_put_time()
1697 if (-1 == width)
1698 width = 0;
1699
1700 prec = 0;
1701
1702 for (; *wpat >= L'0' && *wpat <= L'9'; ++wpat) {
1703 // set the precision of the current specifier
1704 prec = prec * 10 + *wpat - L'0';
1705 }
1706 }
1707 }
1708
1709 char fmtmod = char (*wpat); // format modifier
1710 char fmt; // format specifier
1711
1712 if ('E' == fmtmod && *wpat) {
1713
1714 fmt = char (*++wpat);
1715
1716 switch (fmt) {
1717 // check valid format modifiers
1718 case 'c': case 'C': case 'x': case 'X': case 'y': case 'Y':
1719 break;
1720
1721 case '\0':
1722 break;
1723
1724 default:
1725 fmt = 0; // `wpat' doesn't point to a valid format
1726 }
1727 }
1728 else if ('O' == fmtmod) {
1729
1730 fmt = char (*++wpat);
1731
1732 switch (fmt) {
1733 // check valid format modifiers
1734 case 'd': case 'e': case 'H': case 'I': case 'm': case 'M':
1735 case 'S': case 'u': case 'U': case 'V': case 'w': case 'W':
1736 case 'y':
1737 break;
1738
1739 case '\0':
1740 break;
1741
1742 default:
1743 fmt = 0; // `wpat' doesn't point to a valid format
1744 }
1745 }
1746 else {
1747 fmt = fmtmod;
1748 fmtmod = 0;
1749 }
1750
1751 if (char (-1) != fmt) {
1752 wchar_t* const end =
1753 __rw_put_time (pfacet, wbuf, bufsize, flags, fill,
1754 tmb, fmt, fmtmod, width, prec);
1755
1756 if (!end)
1757 return 0;
1758
1759 wbuf = end;
1760 continue;
1761 }
1762 }
1763
1764 *wbuf++ = *wpat;
1765 }
1766
1767 return wbuf;
1768}
1769
1770#endif // _RWSTD_NO_WCHAR_T
1771
1772
1773// returns true iff `y' is a leap year
1774static inline bool
1775__rw_isleap (int y)
1776{
1777 return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
1778}
1779
1780
1781// returns the ISO 8601 week number from the given date
1782// sets `year' to the ISO 8601 year number for that date
1783static int
1784__rw_iso_week (int& year, int yday, int wday)
1785{
1786 // adjust the week day - tm struct uses a 0-based weekday number
1787 // starting with Sunday, while ISO 8601 week starts with Monday
1788 const int w = (wday + 7 - 1) % 7;
1789
1790 // number of days in the current year
1791 const int y = 365 + __rw_isleap (year);
1792
1793 // number of days between first of January and the first week-end
1794 const int fdoy = (yday + 7 - w) % 7;
1795
1796 int isow;
1797
1798 if (fdoy >= 4) {
1799 // first of Jan belongs to first week
1800 isow = yday + (7 - fdoy);
1801 }
1802 else {
1803 // first of Jan belongs to last week of last year
1804 isow = yday - fdoy;
1805 }
1806
1807 if (isow < 0) {
1808 // the day belongs to last year
1809 year--;
1810 return __rw_iso_week (year, yday + 365 + __rw_isleap (year), wday);
1811 }
1812
1813 // the day could belong to next year; check that
1814 const int r = y - yday;
1815 if (r <= 3 && 3 - r >= w) {
1816 year++;
1817 return w;
1818 }
1819
1820 return isow;
1821}
1822
1823
1824// returns a pointer to the era_t element describing the era
1825// corresponding to the date pointed to by `tmb', or 0 if no
1826// such era exists
1827static const __rw_time_t::era_t*
1828__rw_get_era (const __rw_time_t *ptime, const tm *tmb)
1829{
1830 _RWSTD_ASSERT (0 != tmb);
1831
1832 const int year = 1900 + tmb->tm_year;
1833
1834 // get the number of eras in this locale
1835 const _RWSTD_SIZE_T neras = (_RWSTD_SIZE_T)ptime->era_count ();
1836
1837 for (_RWSTD_SIZE_T i = 0; i != neras; ++i) {
1838 const __rw_time_t::era_t* const pera = ptime->era (i);
1839
1840 _RWSTD_ASSERT (0 != pera);
1841
1842 // offset < 0 implies direction of '-'
1843 // offset >= 0 implies direction of '+'
1844 const int b = pera->offset < 0; // start index
1845 const int e = !b; // end index
1846
1847 // check to see if the specified date belongs to the era
1848 if ( year > pera->year [b] && year < pera->year [e]
1849 || ( (year == pera->year [b] || year == pera->year [e])
1850 && ( tmb->tm_mon > pera->month [b]
1851 && tmb->tm_mon < pera->month [e]
1852 || ( ( tmb->tm_mon == pera->month [b]
1853 || tmb->tm_mon == pera->month [e])
1854 && tmb->tm_mday >= pera->day [b]
1855 && tmb->tm_mday <= pera->day [e])))) {
1856 return pera;
1857 }
1858 }
1859
1860 return 0;
1861}
1862
1863
1864static int
1865__rw_get_zone_off (const char *var, const char **var_end)
1866{
1867 _RWSTD_ASSERT (0 != var);
1868 _RWSTD_ASSERT (0 != var_end);
1869
1870 bool neg = false;
1871
1872 if ('-' == *var) {
1873 neg = true;
1874 ++var;
1875 }
1876 else if ('+' == *var) {
1877 ++var;
1878 }
1879
1880 int offset = 0;
1881
1882 // compute the four-digit offset in the format hhmm from
1883 // the string `var' in the format hh[:mm[:ss]], where
1884 // hh is in the range "0" through "24", and ss and mm
1885 // both in the range "00" through "59"
1886
1887 if (ISDIGIT (*var)) {
1888
1889 offset = *var++ - '0';
1890
1891 if (ISDIGIT (*var)) {
1892 if (offset < 2 || *var >= '0' && *var <= '4') {
1893 // add offset in hours
1894 offset = offset * 10 + *var++ - '0';
1895 }
1896 else
1897 offset = _RWSTD_INT_MIN;
1898 }
1899
1900 if (0 <= offset)
1901 offset *= 100;
1902
1903 if (':' == *var) {
1904
1905 ++var;
1906
1907 if (var [0] >= '0' && var [0] <= '5' && ISDIGIT (var [1])) {
1908 // add offset in minutes
1909 offset += 10 * (*var++ - '0');
1910 offset += (*var++ - '0');
1911
1912 if (':' == *var) {
1913
1914 ++var;
1915
1916 if ( var [0] >= '0' && var [0] <= '5'
1917 && ISDIGIT (var [1])) {
1918
1919 // ignore offset in seconds
1920 var += 2;
1921 }
1922 else {
1923 offset = _RWSTD_INT_MIN;
1924 }
1925 }
1926 }
1927 else {
1928 offset = _RWSTD_INT_MIN;
1929 }
1930 }
1931 }
1932 else {
1933 offset = _RWSTD_INT_MIN;
1934 }
1935
1936 *var_end = var;
1937
1938 return neg ? -offset : offset;
1939}
1940
1941
1942// Also used as a parameter to rw_get_static_mutex to ensure
1943// the uniqueness of the mutex object used in synchronizing
1944// the threads using __rw_get_time_put_data()
1945// (see RWSTD_MT_STATIC_GUARD below)
1946struct __rw_time_put_data
1947{
1948 const void *fmt; // format string to use to format val with
1949 const void *str; // the final formatted string
1950 int val; // numeric value to format
1951 int altval; // value to format using alternative symbols
1952 int width; // the width of numeric output (as in "%*.0d")
1953 int prec; // the precision of numeric output (as in "%0.*d")
1954};
1955
1956
1957static int
1958__rw_get_zone (__rw_time_put_data &tpd, const char *var, int isdst)
1959{
1960 _RWSTD_ASSERT (0 != var);
1961
1962 // TZ format:
1963 // :characters
1964 // or
1965 // std offset[dst[offset][,start[/time],end[/time]]]
1966
1967 int std_off;
1968
1969 if (':' == *var)
1970 goto use_tzset; // can't parse implementation-defined formats
1971
1972 if ('<' == *var) {
1973 // skip past the alphanumeric std designator enclosed in <>
1974 while (*var && '>' != *var++);
1975 }
1976 else {
1977 const char* const stdbeg = var;
1978
1979 // skip past the alphabetic std designator to the beginning
1980 // of the required dst offset; if no dst offset is found,
1981 // the variable is not in the required POSIX format and must
1982 // be handled in an implementation-defined way (i.e., using
1983 // tzset())
1984
1985 for (; ISALPHA (*var); ++var);
1986
1987 if ( var == stdbeg
1988 || *var && '+' != *var && '-' != *var && !ISDIGIT (*var))
1989 goto use_tzset;
1990 }
1991
1992 // get the std offset from TZ in case dst must be computed
1993 std_off = __rw_get_zone_off (var, &var);
1994
1995 if (*var && _RWSTD_INT_MIN != std_off && isdst) {
1996
1997 const char* const dstbeg = var;
1998
1999 if ('<' == *var)
2000 // skip past the quoted alphanumeric dst designator
2001 while (*var && '>' != *var++);
2002 else {
2003 // skip past the alphabetic dst designator
2004 for (; ISALPHA (*var); ++var);
2005 }
2006
2007 if ( var == dstbeg
2008 || *var && '+' != *var && '-' != *var && !ISDIGIT (*var))
2009 goto use_tzset;
2010
2011 tpd.val = __rw_get_zone_off (var, &var);
2012
2013 if (_RWSTD_INT_MIN == tpd.val) {
2014
2015 // failed to extract dst offset from TZ
2016 // check if that's because there was none
2017
2018 if ('\0' == *var) {
2019 // according to SUSv3 (POSIC), if no offset follows dst,
2020 // the alternative time is assumed to be one hour ahead
2021 // of standard time
2022
2023 tpd.val = std_off + 100;
2024
2025 if (2359 < tpd.val)
2026 tpd.val %= 2400;
2027 }
2028 else
2029 goto use_tzset;
2030 }
2031 }
2032 else
2033 goto use_tzset;
2034
2035 return 0; // success
2036
2037use_tzset:
2038
2039 // the lock cannot prevent another thread from calling tzset()
2040 // directly (or one of the other functions in the #else block)
2041 // for "stronger" thread-safety it might be better to take the
2042 // #else branch below and use gmtime_r() there (that would
2043 // only be safe if mktime() were thread-safe)
2044 _RWSTD_MT_STATIC_GUARD (__rw_time_put_data);
2045
2046#ifndef _RWSTD_NO_TIMEZONE
2047
2048 // set the POSIX `timezone' and `daylight' extern variables
2049 tzset ();
2050
2051 // tzet() sets timezone to the difference, in seconds, between
2052 // Coordinated Universal Time (UTC) and local standard time
2053 tpd.val = _RWSTD_STATIC_CAST (int, timezone / 60);
2054
2055#else // if defined (_RWSTD_NO_TIMEZONE)
2056
2057 tpd.val = 0;
2058
2059 // calculate the difference the hard way
2060 static const time_t tgm = 0;
2061
2062 const tm* const tmp = gmtime (&tgm);
2063
2064 if (tmp) {
2065 tm tmgm = *tmp;
2066
2067 const time_t tlocal = mktime (&tmgm);
2068
2069 if (time_t (-1) != tlocal) {
2070
2071 const double diff = difftime (tlocal, tgm);
2072
2073 tpd.val = int (diff / 60);
2074 }
2075 else {
2076 // FIXME: indicate the nature of the error to the caller somehow
2077 return -1;
2078 }
2079 }
2080 else {
2081 // FIXME: indicate the nature of the error to the caller somehow
2082 return -1;
2083 }
2084
2085#endif // _RWSTD_NO_TIMEZONE
2086
2087 // set the value to the difference in the HH:MM "format"
2088 tpd.val = 100 * (tpd.val / 60) + tpd.val % 60;
2089
2090 if (daylight && isdst)
2091 tpd.val += (tpd.val < 0 ? -100 : 100) * isdst;
2092
2093 return 0; // success
2094}
2095
2096
2097static void
2098__rw_get_zone_name (__rw_time_put_data&, const char*, int)
2099{
2100 // FIXME: retrieve tiem zone name from TZ, store it in a suitable
2101 // buffer, and have time_put::put() output the contents of that
2102 // buffer
2103}
2104
2105
2106static void
2107__rw_get_time_put_data (__rw_time_put_data &tpd,
2108 const __rw_facet *facet,
2109 const tm *tmb,
2110 char fmt, char mod, bool wide)
2111{
2112 _RWSTD_ASSERT (0 != facet);
2113
2114 // extension: if `tmb' is 0, output the locale-specific format string
2115 _RWSTD_ASSERT ( 0 != tmb
2116 || 'c' == fmt || 'r' == fmt || 'x' == fmt || 'X' == fmt);
2117
2118 static const union {
2119#ifndef _RWSTD_NO_WCHAR_T
2120 wchar_t wide_data [1];
2121#endif // _RWSTD_NO_WCHAR_T
2122 char data [4];
2123 } null_fmt = { { 0 } };
2124
2125 const __rw_time_t *ptime =
2126 _RWSTD_STATIC_CAST (const __rw_time_t*, facet->_C_data ());
2127
2128 if (!ptime)
2129 ptime = _RWSTD_STATIC_CAST (const __rw_time_t*,
2130 __rw_get_timepunct (facet, 0, 0));
2131
2132 _RWSTD_ASSERT (0 != ptime);
2133
2134 // invalidate data
2135 tpd.fmt = tpd.str = 0;
2136 tpd.val = tpd.altval = _RWSTD_INT_MIN;
2137 tpd.width = tpd.prec = 1;
2138
2139 switch (fmt) {
2140
2141 case 'a':
2142 // %a: the locale's abbreviated weekday name. [tm_wday]
2143 tpd.str = ptime->abday (tmb->tm_wday % 7U, wide);
2144 break;
2145
2146 case 'A':
2147 // %A: the locale's full weekday name. [tm_wday]
2148 tpd.str = ptime->day (tmb->tm_wday % 7U, wide);
2149 break;
2150
2151 case 'b':
2152 // %b: the locale's abbreviated month name. [tm_mon]
2153 tpd.str = ptime->abmon (tmb->tm_mon % 12U, wide);
2154 break;
2155
2156 case 'B':
2157 // %B: the locale's full month name. [tm_mon]
2158 tpd.str = ptime->mon (tmb->tm_mon % 12U, wide);
2159 break;
2160
2161 case 'c':
2162 // %c: the locale's appropriate date and time representation.
2163 // %Ec: the locale's alternative date and time representation.
2164
2165 if ('E' == mod)
2166 tpd.fmt = ptime->era_d_t_fmt (wide);
2167
2168 if ( !tpd.fmt
2169#ifndef _RWSTD_NO_WCHAR_T
2170 || wide && !*_RWSTD_STATIC_CAST (const wchar_t*, tpd.fmt)
2171#endif // _RWSTD_NO_WCHAR_T
2172 || !wide && !*_RWSTD_STATIC_CAST (const char*, tpd.fmt))
2173 tpd.fmt = ptime->d_t_fmt (wide);
2174
2175 _RWSTD_ASSERT (0 != tpd.fmt);
2176 break;
2177
2178 case 'C': {
2179 // %C: the year divided by 100 and truncated to an integer,
2180 // as a decimal number (00-99). [tm_year]
2181 // %EC: the name of the base year (period) in the locale's
2182 // alternative representation.
2183
2184 if ('E' == mod) {
2185 const __rw_time_t::era_t *pera = __rw_get_era (ptime, tmb);
2186
2187 if (pera) {
2188 const _RWSTD_PTRDIFF_T i = pera - ptime->era (0);
2189 tpd.str = ptime->era_name (i, wide);
2190 break;
2191 }
2192 }
2193
2194 // take care to handle negative tm_year
2195 tpd.val = ((1900 + tmb->tm_year) / 100) % 100;
2196 tpd.prec = 2;
2197 break;
2198 }
2199
2200 case 'd':
2201 // %d: the day of the month as a decimal number (01-31). [tm_mday]
2202 // %Od: the day of the month, using the locale's alternative numeric
2203 // symbols (filled as needed with leading zeros, or with leading
2204 // spaces if there is no alternative symbol for zero).
2205
2206 if ('O' == mod)
2207 tpd.altval = tmb->tm_mday;
2208 else
2209 tpd.val = tmb->tm_mday;
2210
2211 tpd.prec = 2;
2212
2213 break;
2214
2215 case 'D': {
2216 // %D: equivalent to "%m/%d/%y". [tm_mon, tm_mday, tm_year]
2217 static const void* const fmats[] = { "%m/%d/%y", L"%m/%d/%y" };
2218
2219 tpd.fmt = fmats [wide];
2220 break;
2221 }
2222
2223 case 'e':
2224 // %e: the day of the month as a decimal number (1-31);
2225 // a single digit is preceded by a space. [tm_mday]
2226 // %Oe: is replaced by the day of the month, using the locale's
2227 // alternative numeric symbols (filled as needed with leading
2228 // spaces).
2229
2230 if ('O' == mod)
2231 tpd.altval = tmb->tm_mday;
2232 else
2233 tpd.val = tmb->tm_mday;
2234
2235 tpd.width = 2;
2236 break;
2237
2238 case 'F': {
2239 // %F: equivalent to "%Y-%m-%d" (the ISO 8601 date format).
2240 // [tm_year, tm_mon, tm_mday]
2241
2242 static const void* const fmats[] = { "%Y-%m-%d", L"%Y-%m-%d" };
2243
2244 tpd.fmt = fmats [wide];
2245 break;
2246 }
2247
2248 case 'g':
2249 // %g: the last 2 digits of the week-based year as a decimal number
2250 // (00-99). [tm_year, tm_wday, tm_yday]
2251
2252 // get the ISO 8601 year
2253 tpd.val = tmb->tm_year + 1900;
2254 __rw_iso_week (tpd.val, tmb->tm_yday, tmb->tm_wday);
2255
2256 tpd.val %= 100;
2257 tpd.prec = 2;
2258 break;
2259
2260 case 'G':
2261 // %G: the week-based year as a decimal number (e.g., 1997).
2262 // [tm_year, tm_wday, tm_yday]
2263
2264 // get the ISO 8601 year
2265 tpd.val = tmb->tm_year + 1900;
2266 __rw_iso_week (tpd.val, tmb->tm_yday, tmb->tm_wday);
2267
2268 break;
2269
2270 case 'h':
2271 // %h: equivalent to "%b". [tm_mon]
2272 tpd.fmt = ptime->abmon (tmb->tm_mon % 12U, wide);
2273 break;
2274
2275 case 'k':
2276 // %k: the hour (24-hour clock) as a decimal number (0-23)
2277 // with single digits preceded by a blank. [tm_hour]
2278 // this is a popular extension implemented for example
2279 // on AIX, Linux and Solaris
2280 tpd.width = 2;
2281 // fall through
2282
2283 case 'H':
2284 // %H: the hour (24-hour clock) as a decimal number (00-23). [tm_hour]
2285 // %OH: the hour (24-hour clock), using the locale's alternative
2286 // numeric symbols.
2287
2288 if ('O' == mod)
2289 tpd.altval = tmb->tm_hour;
2290 else
2291 tpd.val = tmb->tm_hour;
2292
2293 // set precision only for "%H" and not for "%k"
2294 // (i.e., when width hasn't been overridden above)
2295 if (1 == tpd.width)
2296 tpd.prec = 2;
2297 break;
2298
2299 case 'l':
2300 // %l: the hour (12-hour clock) as a decimal number (1,12)
2301 // with single digits preceded by a blank. [tm_hour]
2302 // this is a popular extension implemented for example
2303 // on Linux and Solaris
2304 tpd.width = 2;
2305 // fall through
2306
2307 case 'I': {
2308 // %I: the hour (12-hour clock) as a decimal number (01-12). [tm_hour]
2309 // %OI: the hour (12-hour clock), using the locale's alternative
2310 // numeric symbols.
2311
2312 unsigned hour = tmb->tm_hour % 12;
2313 if (!hour)
2314 hour = 12;
2315
2316 if ('O' == mod)
2317 tpd.altval = hour;
2318 else
2319 tpd.val = hour;
2320
2321 // set precision only for "%I" and not for "%l"
2322 // (i.e., when width hasn't been overridden above)
2323 if (1 == tpd.width)
2324 tpd.prec = 2;
2325
2326 break;
2327 }
2328
2329 case 'j':
2330 // %j: the day of the year as a decimal number (001-366). [tm_yday]
2331
2332 tpd.val = tmb->tm_yday + 1;
2333 tpd.prec = 3;
2334 break;
2335
2336 case 'm':
2337 // %m: the month as a decimal number (01-12). [tm_mon]
2338 // %Om: the month, using the locale's alternative numeric symbols.
2339
2340 if ('O' == mod)
2341 tpd.altval = tmb->tm_mon + 1;
2342 else
2343 tpd.val = tmb->tm_mon + 1;
2344
2345 tpd.prec = 2;
2346 break;
2347
2348 case 'M':
2349 // %M: the minute as a decimal number (00-59). [tm_min]
2350 // %OM: the minutes, using the locale's alternative numeric symbols.
2351
2352 if ('O' == mod)
2353 tpd.altval = tmb->tm_min;
2354 else
2355 tpd.val = tmb->tm_min;
2356
2357 tpd.prec = 2;
2358 break;
2359
2360 case 'n': {
2361 // %n: a new-line character.
2362 static const void* const fmats [] = { "\n", L"\n" };
2363 tpd.str = fmats [wide];
2364 break;
2365 }
2366
2367 case 'p':
2368 // %p: the locale's equivalent of the AM/PM designations
2369 // associated with a 12-hour clock. [tm_hour]
2370 tpd.fmt = ptime->am_pm ((tmb->tm_hour / 12) % 2U, wide);
2371 break;
2372
2373 case 'r':
2374 // %r: the locale's 12-hour clock time. [tm_hour, tm_min, tm_sec]
2375 tpd.fmt = ptime->t_fmt_ampm (wide);
2376 break;
2377
2378 case 'R': {
2379 // %R: equivalent to "%H:%M". [tm_hour, tm_min]
2380 static const void* const fmats[] = { "%H:%M", L"%H:%M" };
2381
2382 tpd.fmt = fmats [wide];
2383 break;
2384 }
2385
2386 case 'S':
2387 // %S: the second as a decimal number (00-60). [tm_sec]
2388 // %OS: the seconds, using the locale's alternative numeric symbols.
2389
2390 if ('O' == mod)
2391 tpd.altval = tmb->tm_sec;
2392 else
2393 tpd.val = tmb->tm_sec;
2394
2395 tpd.prec = 2;
2396 break;
2397
2398 case 't': {
2399 // %t: a horizontal-tab character.
2400 static const void* const fmats[] = { "\t", L"\t" };
2401
2402 tpd.str = fmats [wide];
2403 break;
2404 }
2405
2406 case 'T': {
2407 // %T: equivalent to "%H:%M:%S" (the ISO 8601 time format).
2408 // [tm_hour, tm_min, tm_sec]
2409 static const void* const fmats[] = { "%H:%M:%S", L"%H:%M:%S" };
2410
2411 tpd.fmt = fmats [wide];
2412 break;
2413 }
2414
2415 case 'u':
2416 // %u: the ISO 8601 weekday as a decimal number (1-7),
2417 // where Monday is 1. [tm_wday]
2418 // %Ou: the ISO 8601 weekday as a number in the locale's alternative
2419 // representation, where Monday is 1.
2420
2421 if ('O' == mod)
2422 tpd.altval = 1 + (tmb->tm_wday ? tmb->tm_wday - 1 : 6);
2423 else
2424 tpd.val = 1 + (tmb->tm_wday ? tmb->tm_wday - 1 : 6);
2425
2426 break;
2427
2428 case 'U': {
2429 // %U: the week number of the year (the first Sunday as the first
2430 // day of week 1) as a decimal number (00-53).
2431 // [tm_year, tm_wday, tm_yday]
2432 // %OU: the week number, using the locale's alternative numeric
2433 // symbols.
2434
2435 const int week = (tmb->tm_yday - tmb->tm_wday + 7) / 7;
2436
2437 if ('O' == mod)
2438 tpd.altval = week;
2439 else
2440 tpd.val = week;
2441
2442 tpd.prec = 2;
2443 break;
2444 }
2445
2446 case 'V': {
2447 // %V: the ISO 8601 week number (see below) as a decimal number
2448 // (01-53). [tm_year, tm_wday, tm_yday]
2449 // %OV: the ISO 8601 week number, using the locale's alternative
2450 // numeric symbols.
2451
2452 int year = tmb->tm_year + 1900;
2453 const int week =
2454 __rw_iso_week (year, tmb->tm_yday, tmb->tm_wday) / 7 + 1;
2455
2456 if ('O' == mod)
2457 tpd.altval = week;
2458 else
2459 tpd.val = week;
2460
2461 tpd.prec = 2;
2462 break;
2463 }
2464
2465 case 'w':
2466 // %w: the weekday as a decimal number (0-6), where Sunday is 0.
2467 // [tm_wday]
2468 // %Ow: the weekday as a number, using the locale's alternative
2469 // numeric symbols.
2470
2471 if ('O' == mod)
2472 tpd.altval = tmb->tm_wday;
2473 else
2474 tpd.val = tmb->tm_wday;
2475
2476 break;
2477
2478 case 'W': {
2479 // %W: the week number of the year (the first Monday as the first
2480 // day of week 1) as a decimal number (00-53).
2481 // [tm_year, tm_wday, tm_yday]
2482 // %OW: the week number of the year, using the locale's alternative
2483 // numeric symbols.
2484
2485 const int week = (tmb->tm_yday - (tmb->tm_wday - 1 + 7) % 7 + 7) / 7;
2486
2487 if ('O' == mod)
2488 tpd.altval = week;
2489 else
2490 tpd.val = week;
2491
2492 tpd.prec = 2;
2493 break;
2494 }
2495
2496 case 'x':
2497 // %x: the locale's appropriate date representation.
2498 // %Ex: the locale's alternative date representation.
2499
2500 if ('E' == mod)
2501 tpd.fmt = ptime->era_d_fmt (wide);
2502
2503 if ( !tpd.fmt
2504#ifndef _RWSTD_NO_WCHAR_T
2505 || wide && !*_RWSTD_STATIC_CAST (const wchar_t*, tpd.fmt)
2506#endif // _RWSTD_NO_WCHAR_T
2507 || !wide && !*_RWSTD_STATIC_CAST (const char*, tpd.fmt))
2508 tpd.fmt = ptime->d_fmt (wide);
2509
2510 break;
2511
2512 case 'X':
2513 // %X: the locale's appropriate time representation.
2514 // %EX: the locale's alternative time representation.
2515
2516 if ('E' == mod)
2517 tpd.fmt = ptime->era_t_fmt (wide);
2518
2519 if ( !tpd.fmt
2520#ifndef _RWSTD_NO_WCHAR_T
2521 || wide && !*_RWSTD_STATIC_CAST (const wchar_t*, tpd.fmt)
2522#endif // _RWSTD_NO_WCHAR_T
2523 || !wide && !*_RWSTD_STATIC_CAST (const char*, tpd.fmt))
2524 tpd.fmt = ptime->t_fmt (wide);
2525
2526 break;
2527
2528 case 'y':
2529 // %y: the last 2 digits of the year as a decimal number (00-99).
2530 // [tm_year]
2531 // %Ey: the offset from %EC (year only) in the locale's alternative
2533 // %Oy: the last 2 digits of the year, using the locale's alternative
2534 // numeric symbols.
2535
2536 if ('E' == mod) {
2537
2538 const __rw_time_t::era_t* const pera = __rw_get_era (ptime, tmb);
2539
2540 if (pera) {
2541 tpd.altval = pera->offset < 0
2542 ? pera->year [0] - 1900 - tmb->tm_year - pera->offset
2543 : 1900 + tmb->tm_year - pera->year [0] + pera->offset;
2544
2545 break;
2546 }
2547 }
2548
2549 if ('O' == mod)
2550 tpd.altval = (1900 + tmb->tm_year) % 100;
2551 else
2552 tpd.val = (1900 + tmb->tm_year) % 100;
2553
2554 tpd.prec = 2;
2555 break;
2556
2557 case 'Y':
2558 // %Y: the year as a decimal number (e.g., 1997). [tm_year]
2559 // %EY: the locale's full alternative year representation.
2560
2561 if (mod) {
2562 const __rw_time_t::era_t* const pera = __rw_get_era (ptime, tmb);
2563
2564 if ( pera
2565 && !!(tpd.fmt = ptime->era_fmt (pera - ptime->era (0), wide)))
2566 break;
2567 }
2568
2569 tpd.val = 1900 + tmb->tm_year;
2570 break;
2571
2572 case 'z':
2573 // %z: the offset from UTC in the ISO 8601:2000 standard format
2574 // (+hhmm or -hhmm), or by no characters if no timezone is
2575 // determinable.
2576 // For example, "-0430" means 4 hours 30 minutes behind UTC
2577 // (west of Greenwich).
2578 // If tm_isdst is zero, the standard time offset is used.
2579 // If tm_isdst is greater than zero, the daylight savings
2580 // time offset is used.
2581 // If tm_isdst is negative, no characters are returned.
2582 // [tm_isdst]
2583
2584 if (tmb->tm_isdst < 0) {
2585 // force no output
2586 tpd.val = _RWSTD_INT_MIN;
2587 tpd.fmt = null_fmt.data;
2588 break;
2589 }
2590
2591 // fall through
2592
2593 case 'Z': {
2594 // %Z: the locale's time zone name or abbreviation, or no
2595 // characters if no time zone is determinable. [tm_isdst]
2596
2597 if ('z' == fmt) {
2598
2599 tpd.prec = 4;
2600
2601#if defined (__GLIBC__) && defined (_RWSTD_NO_PURE_C_HEADERS)
2602
2603 // GNU glibc uses gmtoff and zone instead of timezone and
2604 // tzname when computing/formatting time zone information
2605
2606# if defined (__STRICT_ANSI__) && !defined (__USE_BSD)
2607
2608 tpd.val = tmb->__tm_gmtoff;
2609
2610# else // if !defined (__STRICT_ANSI__) || defined (__USE_BSD)
2611
2612 tpd.val = tmb->tm_gmtoff;
2613
2614# endif // __STRICT_ANSI__, __USE_BSD
2615
2616 if (tpd.val) {
2617
2618 // use the offset from GMT only if it's non-zero
2619 // and ignore the tm_isdst flag (glibc behavior)
2620 tpd.val /= 60;
2621 tpd.val = 100 * (tpd.val / 60) + tpd.val % 60;
2622
2623 break;
2624 }
2625
2626 // otherwise (0 GMT offset), use the TZ environment variable
2627 // to determine the global offset and consider the tm_isdst
2628 // flag (POSIX behavior)
2629
2630#endif // __GLIBC__ && _RWSTD_NO_PURE_C_HEADERS
2631
2632 const char* const var = getenv ("TZ");
2633
2634 if (!var || !*var || __rw_get_zone (tpd, var, tmb->tm_isdst)) {
2635 // force no output on error
2636 tpd.val = _RWSTD_INT_MIN;
2637 tpd.fmt = null_fmt.data;
2638 break;
2639 }
2640 }
2641 else {
2642 const char* const var = getenv ("TZ");
2643
2644 if (!var || !*var) {
2645 // force no output
2646 tpd.val = _RWSTD_INT_MIN;
2647 tpd.fmt = null_fmt.data;
2648 break;
2649 }
2650
2651 __rw_get_zone_name (tpd, var, tmb->tm_isdst);
2652 }
2653
2654 break;
2655 }
2656
2657 case '%': {
2658 static const void* const fmats[] = { "%", L"%" };
2659
2660 tpd.str = fmats [wide];
2661 break;
2662 }
2663
2664 default: break;
2665 }
2666}
2667
2668
2669_RWSTD_EXPORT char*
2670__rw_put_time (const __rw_facet *facet, char *buf, _RWSTD_SIZE_T bufsize,
2671 _STD::ios_base &flags, char fill, const tm *tmb,
2672 char fmt, char mod, int width, int prec)
2673{
2674 _RWSTD_ASSERT (0 != facet);
2675
2676 _RWSTD_SIZE_T res = 0; // size of formatted output, -1 on error
2677
2678 // compute the values and get the format
2679 __rw_time_put_data tpd;
2680 __rw_get_time_put_data (tpd, facet, tmb, fmt, mod, false /* narrow */);
2681
2682 if (_RWSTD_INT_MIN != tpd.altval) {
2683
2684 // retrieve the alternative numeric symbols (if any)
2685
2686 const __rw_time_t *ptime =
2687 _RWSTD_STATIC_CAST (const __rw_time_t*, facet->_C_data ());
2688
2689 _RWSTD_ASSERT (0 != ptime);
2690
2691 const _RWSTD_UINT32_T ndigits = ptime->alt_digits_count ();
2692
2693 const _RWSTD_UINT32_T altval =
2694 _RWSTD_STATIC_CAST (_RWSTD_UINT32_T, tpd.altval);
2695
2696 if (altval < ndigits) {
2697
2698 // format using alternative numeric symbols
2699 const char* digit =
2700 _RWSTD_STATIC_CAST (const char*, ptime->alt_digits (altval, 0));
2701
2702 _RWSTD_ASSERT (digit);
2703
2704 char *pbuf = buf;
2705
2706 while (*digit)
2707 *pbuf++ = *digit++;
2708
2709 return pbuf;
2710 }
2711
2712 // if the value exceeds the range representable by the available
2713 // alternative numeric symbols, format using ordinary digits
2714 tpd.val = tpd.altval;
2715 }
2716
2717 if (_RWSTD_INT_MIN != tpd.val) {
2718
2719 const char* const fmtstr = 'z' == fmt ? "%+*.*d" : "%*.*d";
2720
2721 res = (_RWSTD_SIZE_T)sprintf (buf, fmtstr,
2722 width < 0 ? tpd.width : width,
2723 prec < 0 ? tpd.prec : prec, tpd.val);
2724 }
2725 else {
2726 if (!tmb && tpd.fmt) {
2727 tpd.str = tpd.fmt;
2728 tpd.fmt = 0;
2729 }
2730
2731 if (tpd.fmt) {
2732
2733 const char* const fmtstr =
2734 _RWSTD_STATIC_CAST (const char*, tpd.fmt);
2735
2736 return __rw_fmt_time (facet, buf, bufsize, flags,
2737 fill, tmb, fmtstr);
2738 }
2739
2740 if (tpd.str) {
2741 // copy data if available
2742
2743 const char *src = _RWSTD_STATIC_CAST (const char*, tpd.str);
2744
2745 for (char *dst = buf; *src && res < bufsize; ++src, ++dst, ++res)
2746 *dst = *src;
2747
2748 _RWSTD_ASSERT (bufsize >= res);
2749 }
2750 else {
2751 char fmtstr [4] = { '%', fmt, '\0', '\0' };
2752
2753 if (mod) {
2754 fmtstr [1] = mod;
2755 fmtstr [2] = fmt;
2756 }
2757
2758 // use strftime() for locale-independent formatting
2759 res = strftime (buf, bufsize, fmtstr, tmb);
2760
2761 _RWSTD_ASSERT (bufsize > res);
2762 }
2763 }
2764
2765 return buf + res;
2766}
2767
2768
2769#ifndef _RWSTD_NO_WCHAR_T
2770
2771_RWSTD_EXPORT wchar_t*
2772__rw_put_time (const __rw_facet *facet, wchar_t *wbuf, _RWSTD_SIZE_T bufsize,
2773 _STD::ios_base &flags, wchar_t fill, const tm *tmb,
2774 char fmt, char mod, int width, int prec)
2775{
2776 _RWSTD_ASSERT (0 != facet);
2777
2778 _RWSTD_SIZE_T res = 0; // size of formatted output, -1 on error
2779
2780 __rw_time_put_data tpd;
2781
2782 __rw_get_time_put_data (tpd, facet, tmb, fmt, mod, true /* wide */);
2783
2784 if (_RWSTD_INT_MIN != tpd.altval) {
2785
2786 const __rw_time_t *ptime =
2787 _RWSTD_STATIC_CAST (const __rw_time_t*, facet->_C_data ());
2788
2789 _RWSTD_ASSERT (0 != ptime);
2790
2791 const _RWSTD_UINT32_T n = ptime->alt_digits_count ();
2792
2793 if (tpd.altval >= 0 && tpd.altval < int (n)) {
2794
2795 const _RWSTD_SIZE_T altval =
2796 _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, tpd.altval);
2797
2798 // format using alternative numeric symbols
2799 const wchar_t* digit =
2800 _RWSTD_STATIC_CAST (const wchar_t*, ptime->alt_digits (altval, 1));
2801
2802 _RWSTD_ASSERT (digit);
2803
2804 wchar_t *pbuf = wbuf;
2805
2806 while (*digit)
2807 *pbuf++ = *digit++;
2808
2809 return pbuf;
2810 }
2811
2812 // format using ordinary digits
2813 tpd.val = tpd.altval;
2814 }
2815
2816 if (_RWSTD_INT_MIN != tpd.val) {
2817
2818#ifndef _RWSTD_NO_SWPRINTF
2819
2820 const wchar_t *fmtstr = 'z' == fmt ? L"%+*.*d" : L"%*.*d";
2821
2822 res = swprintf (wbuf,
2823#if !defined (__MINGW32__) && (!defined (_MSC_VER) || 1400 <= _MSC_VER)
2824 // MSVC 8.0 changed swprintf() to conform
2825 // to the C standard signature
2826 bufsize,
2827#endif // not MSVC || MSVC >= 8.0
2828 fmtstr,
2829 width < 0 ? tpd.width : width,
2830 prec < 0 ? tpd.prec : prec, tpd.val);
2831
2832#else // if defined (_RWSTD_NO_SWPRINTF)
2833
2834 const char *fmtstr = 'z' == fmt ? "%+*.*d" : "%*.*d";
2835
2836 char buf [64];
2837
2838 res = (_RWSTD_SIZE_T)::sprintf (buf, fmtstr,
2839 width < 0 ? tpd.width : width,
2840 prec < 0 ? tpd.prec : prec, tpd.val);
2841
2842 _RWSTD_ASSERT (res < sizeof buf);
2843
2844 wchar_t *dst = wbuf;
2845
2846 for (const char *s = buf; *s; ++s, ++dst)
2847 *dst = _RWSTD_STATIC_CAST (unsigned char, *s);
2848
2849 res = dst - wbuf;
2850
2851#endif // _RWSTD_NO_SWPRINTF
2852
2853 }
2854 else {
2855 if (!tmb && tpd.fmt) {
2856 tpd.str = tpd.fmt;
2857 tpd.fmt = 0;
2858 }
2859
2860 if (tpd.fmt) {
2861
2862 const wchar_t* const wfmt =
2863 _RWSTD_STATIC_CAST (const wchar_t*, tpd.fmt);
2864
2865 return __rw_fmt_time (facet, wbuf, bufsize, flags, fill, tmb, wfmt);
2866 }
2867
2868 if (tpd.str) {
2869 // copy data if available
2870
2871 const wchar_t *src = _RWSTD_STATIC_CAST (const wchar_t*, tpd.str);
2872
2873 for (wchar_t *dst = wbuf; *src && res < bufsize; ++src, ++dst, ++res)
2874 *dst = *src;
2875
2876 _RWSTD_ASSERT (bufsize >= res);
2877 }
2878 else {
2879
2880#if !defined (_RWSTD_NO_WCSFTIME_WCHAR_T_FMAT) && !defined (_RWSTD_NO_WCSFTIME)
2881
2882 wchar_t fmtstr [4] = { L'%', fmt, L'\0', L'\0' };
2883
2884#else // if _RWSTD_NO_WCSFTIME_WCHAR_T_FMAT || _RWSTD_NO_WCSFTIME
2885
2886 // work around incorrect wcsftime() declarations some
2887 // platforms
2888 char fmtstr [4] = { '%', fmt, '\0', '\0' };
2889
2890#endif // !_RWSTD_NO_WCSFTIME_WCHAR_T_FMAT && !_RWSTD_NO_WCSFTIME
2891
2892 if (mod) {
2893 fmtstr [1] = mod;
2894 fmtstr [2] = fmt;
2895 }
2896
2897#ifndef _RWSTD_NO_WCSFTIME
2898
2899 // use wcsftime() for locale-independent formatting
2900 res = wcsftime (wbuf, bufsize, fmtstr, tmb);
2901
2902 _RWSTD_ASSERT (res < bufsize);
2903
2904#else // if defined (_RWSTD_NO_WCSFTIME)
2905
2906 char buf [256];
2907
2908 // use strftime() for locale-independent formatting
2909 res = strftime (buf, sizeof buf, fmtstr, tmb);
2910
2911 if (res <= sizeof buf) {
2912 // widen narrow (not multibyte) result into wide buffer
2913 for (_RWSTD_SIZE_T i = 0; i != res; ++i)
2914 wbuf [i] = _RWSTD_STATIC_CAST (unsigned char, buf [i]);
2915 }
2916
2917#endif // _RWSTD_NO_WCSFTIME
2918 }
2919 }
2920
2921 return wbuf + res;
2922}
2923
2924#endif // _RWSTD_NO_WCHAR_T
2925
2926
2927} // namespace __rw
void count(T, T, const U &,...)
#define i
Definition 17.names.cpp:126
#define y
Definition 17.names.cpp:141
#define var
Definition 17.names.cpp:573
#define t
Definition 17.names.cpp:136
#define cnt
Definition 17.names.cpp:459
#define e
Definition 17.names.cpp:118
#define start
Definition 17.names.cpp:547
#define res
Definition 17.names.cpp:531
#define r
Definition 17.names.cpp:134
#define w
Definition 17.names.cpp:139
#define neg
Definition 17.names.cpp:503
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define off
Definition 17.names.cpp:507
#define offset
Definition 17.names.cpp:508
#define b
Definition 17.names.cpp:110
#define tmp
Definition 17.names.cpp:553
#define s
#define len
Definition 17.names.cpp:488
#define n
Definition 17.names.cpp:130
#define inx
Definition 17.names.cpp:484
#define val
Definition 17.names.cpp:570
const char *const data[]
#define flags
const int end
unsigned short wchar_t
#define _RWSTD_EXPORT
Definition _defs.h:485
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _LIBC_THROWS()
Definition _defs.h:1152
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
#define _RWSTD_MT_STATIC_GUARD(name)
Definition _defs.h:696
int nl_item
Definition catalog.h:129
const char * str
Definition exec.cpp:170
unsigned char UChar
Definition collate.cpp:122
#define ISDIGIT(c)
#define ENTRY(item, mem1, mem2)
#define ISALPHA(c)