ReactOS 0.4.16-dev-736-g28b802b
wcsftime.cpp
Go to the documentation of this file.
1//
2// wcsftime.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// The wcsftime family of functions, which format time data into a wide string,
7// and related functionality.
8//
10#include <stdlib.h>
11#include <locale.h>
12
13
14//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15//
16// Day and Month Name and Time Locale Information Fetching Functions
17//
18//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19extern "C" wchar_t* __cdecl _W_Getdays()
20{
21 _LocaleUpdate locale_update(nullptr);
22 __crt_lc_time_data const* const time_data = locale_update.GetLocaleT()->locinfo->lc_time_curr;
23
24 size_t length = 0;
25 for (size_t n = 0; n < 7; ++n)
26 {
27 length += wcslen(time_data->_W_wday_abbr[n]) + wcslen(time_data->_W_wday[n]) + 2;
28 }
29
30 __crt_unique_heap_ptr<wchar_t> buffer(_malloc_crt_t(wchar_t, length + 1));
31 if (buffer.get() == nullptr)
32 return nullptr;
33
34 wchar_t* it = buffer.get();
35 for (size_t n = 0; n < 7; ++n)
36 {
37 *it++ = L':';
38 _ERRCHECK(wcscpy_s(it, (length + 1) - (it - buffer.get()), time_data->_W_wday_abbr[n]));
39 it += wcslen(it);
40 *it++ = L':';
41 _ERRCHECK(wcscpy_s(it, (length + 1) - (it - buffer.get()), time_data->_W_wday[n]));
42 it += wcslen(it);
43 }
44 *it++ = L'\0';
45
46 return buffer.detach();
47}
48
49
50
51extern "C" wchar_t* __cdecl _W_Getmonths()
52{
53 _LocaleUpdate locale_update(nullptr);
54 __crt_lc_time_data const* const time_data = locale_update.GetLocaleT()->locinfo->lc_time_curr;
55
56 size_t length = 0;
57 for (size_t n = 0; n < 12; ++n)
58 {
59 length += wcslen(time_data->_W_month_abbr[n]) + wcslen(time_data->_W_month[n]) + 2;
60 }
61
62 __crt_unique_heap_ptr<wchar_t> buffer(_malloc_crt_t(wchar_t, length + 1));
63 if (buffer.get() == nullptr)
64 return nullptr;
65
66 wchar_t* it = buffer.get();
67 for (size_t n = 0; n < 12; ++n)
68 {
69 *it++ = L':';
70 _ERRCHECK(wcscpy_s(it, (length + 1) - (it - buffer.get()), time_data->_W_month_abbr[n]));
71 it += wcslen(it);
72 *it++ = L':';
73 _ERRCHECK(wcscpy_s(it, (length + 1) - (it - buffer.get()), time_data->_W_month[n]));
74 it += wcslen(it);
75 }
76 *it++ = L'\0';
77
78 return buffer.detach();
79}
80
81
82
83extern "C" void* __cdecl _W_Gettnames()
84{
85 _LocaleUpdate locale_update(nullptr);
86 __crt_lc_time_data const* const src = locale_update.GetLocaleT()->locinfo->lc_time_curr;
87
88
89
90 #define PROCESS_STRING(STR, CHAR, CPY, LEN) \
91 while (bytes % sizeof(CHAR) != 0) \
92 { \
93 ++bytes; \
94 } \
95 if (phase == 1) \
96 { \
97 dest->STR = ((CHAR *) dest) + bytes / sizeof(CHAR); \
98 _ERRCHECK(CPY(dest->STR, (total_bytes - bytes) / sizeof(CHAR), src->STR)); \
99 } \
100 bytes += (LEN(src->STR) + 1) * sizeof(CHAR);
101
102 #define PROCESS_NARROW_STRING(STR) \
103 PROCESS_STRING(STR, char, strcpy_s, strlen)
104
105 #define PROCESS_WIDE_STRING(STR) \
106 PROCESS_STRING(STR, wchar_t, wcscpy_s, wcslen)
107
108 #define PROCESS_NARROW_ARRAY(ARR) \
109 for (size_t idx = 0; idx < _countof(src->ARR); ++idx) \
110 { \
111 PROCESS_NARROW_STRING(ARR[idx]) \
112 }
113
114 #define PROCESS_WIDE_ARRAY(ARR) \
115 for (size_t idx = 0; idx < _countof(src->ARR); ++idx) \
116 { \
117 PROCESS_WIDE_STRING(ARR[idx]) \
118 }
119
120
121 size_t total_bytes = 0;
122 size_t bytes = sizeof(__crt_lc_time_data);
123
124 __crt_lc_time_data* dest = nullptr;
125 for (int phase = 0; phase < 2; ++phase)
126 {
127 if (phase == 1)
128 {
129 dest = static_cast<__crt_lc_time_data*>(_malloc_crt(bytes));
130
131 if (!dest) {
132 return nullptr;
133 }
134
135 memset(dest, 0, bytes);
136
137 total_bytes = bytes;
138
139 bytes = sizeof(__crt_lc_time_data);
140 }
141
142 PROCESS_NARROW_ARRAY(wday_abbr)
144 PROCESS_NARROW_ARRAY(month_abbr)
147 PROCESS_NARROW_STRING(ww_sdatefmt)
148 PROCESS_NARROW_STRING(ww_ldatefmt)
149 PROCESS_NARROW_STRING(ww_timefmt)
150
151 if (phase == 1)
152 {
153 dest->ww_caltype = src->ww_caltype;
154 dest->refcount = 0;
155 }
156
157 PROCESS_WIDE_ARRAY(_W_wday_abbr)
158 PROCESS_WIDE_ARRAY(_W_wday)
159 PROCESS_WIDE_ARRAY(_W_month_abbr)
160 PROCESS_WIDE_ARRAY(_W_month)
161 PROCESS_WIDE_ARRAY(_W_ampm)
162 PROCESS_WIDE_STRING(_W_ww_sdatefmt)
163 PROCESS_WIDE_STRING(_W_ww_ldatefmt)
164 PROCESS_WIDE_STRING(_W_ww_timefmt)
165 PROCESS_WIDE_STRING(_W_ww_locale_name)
166 }
167
168 return dest;
169}
170
171
172
173//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174//
175// Local Functions Used In Time String Formatting
176//
177//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
178// Values for __crt_lc_time_data ww_* fields for store_winword:
179#define WW_SDATEFMT 0
180#define WW_LDATEFMT 1
181#define WW_TIMEFMT 2
182
183// Note: annotation does not account for fact < *count bytes may be written if null terminator hit
184#define _CrtWcstime_Writes_and_advances_ptr_(count) \
185 _Outptr_result_buffer_(count)
186
187
188// Copies the supplied time string 'in' into the output buffer 'out' until either
189// (a) the end of the time string is reached or (b) '*count' becomes zero (and we
190// run out of buffer space). The '*out' pointer is updated to point to the next
191// character in the buffer (one-past-the-end of the insertion), and the '*count'
192// value is updated to reflect the number of characters written.
194 _In_reads_or_z_(*count) wchar_t const* in,
196 _Inout_ size_t* const count
197 ) throw()
198{
199 while (*count != 0 && *in != L'\0')
200 {
201 *(*out)++ = *in++;
202 --*count;
203 }
204}
205
206
207
208// Converts a positive integer ('value') into a string and stores it in the
209// 'output' buffer. It stops writing when either (a) the full value has been
210// printed, or (b) '*count' becomes zero (and we run out of buffer space). The
211// '*out' pointer is updated to point to the next character in the buffer (one-
212// past-the-end of the insertion), and the '*count' value is updated to reflect
213// the number of characters written.
215 int value,
217 _Inout_ size_t* const count
218 ) throw()
219{
220 // Put the digits in the buffer in reverse order:
221 wchar_t* out_it = *out;
222 if (*count > 1)
223 {
224 do
225 {
226 *out_it++ = static_cast<wchar_t>(value % 10 + L'0');
227
228 value /= 10;
229 --*count;
230 }
231 while (value > 0 && *count > 1);
232 }
233 else
234 {
235 // Indicate buffer too small.
236 *out -= *count;
237 *count = 0;
238 return;
239 }
240
241 wchar_t* left = *out;
242 wchar_t* right = out_it - 1;
243
244 // Update the output iterator to point to the next space:
245 *out = out_it;
246
247 // Reverse the buffer:
248 while (left < right)
249 {
250 wchar_t const x = *right;
251 *right-- = *left;
252 *left++ = x;
253 }
254}
255
256
257
258// Converts a positive integer ('value') into a string and stores it in the
259// 'output' buffer. Both '*out' and '*count' are updated to reflect the
260// write.
262 int value,
263 int digits,
265 _Inout_ size_t* const count,
266 wchar_t const pad_character
267 ) throw()
268{
269 if (pad_character == '\0')
270 {
272 return;
273 }
274
275 if (static_cast<size_t>(digits) < *count)
276 {
277 int temp = 0;
278 for (digits--; digits + 1 != 0; --digits)
279 {
280 if (value != 0)
281 {
282 (*out)[digits] = static_cast<wchar_t>(L'0' + value % 10);
283 }
284 else
285 {
286 (*out)[digits] = pad_character;
287 }
288
289 value /= 10;
290 temp++;
291 }
292
293 *out += temp;
294 *count -= temp;
295 }
296 else
297 {
298 *count = 0;
299 }
300}
301
302
303
304//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
305//
306// Local Functions Used for ISO Week-Based Year Computations
307//
308//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
309enum
310{
317 saturday = 6
319
320static int compute_week_of_year(int const wstart, int const wday, int const yday) throw()
321{
322 int const adjusted_wday{(wday + 7 - wstart) % 7};
323 return (yday + 7 - adjusted_wday) / 7;
324}
325
326static int __cdecl compute_iso_week_internal(int year, int wday, int yday) throw()
327{
328 int const week_number{compute_week_of_year(monday, wday, yday)};
329 bool const is_leap_year{__crt_time_is_leap_year(year)};
330
331 int const yunleap{yday - is_leap_year};
332 int const jan1{(371 - yday + wday) % 7};
333 int const dec32{(jan1 + is_leap_year + 365) % 7};
334
335 if ((364 <= yunleap && dec32 == tuesday ) ||
336 (363 <= yunleap && dec32 == wednesday) ||
337 (362 <= yunleap && dec32 == thursday ))
338 {
339 return -1; // Push into the next year
340 }
341 else if (jan1 == tuesday || jan1 == wednesday || jan1 == thursday)
342 {
343 return week_number + 1;
344 }
345
346 return week_number;
347}
348
349static int __cdecl compute_iso_week(int const year, int const wday, int const yday) throw()
350{
351 int const week_number{compute_iso_week_internal(year, wday, yday)};
352
353 if (week_number == 0)
354 return compute_iso_week_internal(year - 1, wday + 7 - yday, __crt_time_is_leap_year(year - 1) ? 366 : 365);
355
356 if (0 < week_number)
357 return week_number;
358
359 return 1;
360}
361
362static int __cdecl compute_iso_year(int const year, int const wday, int const yday) throw()
363{
364 int const week_number{compute_iso_week_internal(year, wday, yday)};
365
366 if (week_number == 0)
367 return year - 1;
368
369 if (0 < week_number)
370 return year;
371
372 return year + 1;
373}
374
375
376
377// store_winword and expand_time are mutually recursive
378_Success_(return)
379static bool __cdecl expand_time(
381 wchar_t specifier,
382 tm const* tmptr,
384 _Inout_ size_t* count,
386 bool alternate_form
387 ) throw();
388
389
390
391// Formats the date and time in the supplied WinWord format and stores the
392// formatted result in the supplied buffer. For simple localized Gregorian
393// calendars (calendar type 1), the WinWord format is converted token-by-token
394// to wcsftime conversion specifiers. expand_time is then called to do the
395// heavy lifting. For other calendar types, the Windows APIs GetDateFormatEx
396// and GetTimeFormatEx are instead used to do all the formatting, so this
397// function does not need to know about era and period strings, year offsets,
398// etc. Returns true on success; false on failure.
399_Success_(return)
400static bool __cdecl store_winword(
401 _locale_t const locale,
402 int const field_code,
403 tm const* const tmptr,
405 _Inout_ size_t* const count,
406 __crt_lc_time_data const* const lc_time
408{
409 wchar_t const* format;
410 switch (field_code)
411 {
412 case WW_SDATEFMT:
413 format = lc_time->_W_ww_sdatefmt;
414 break;
415
416 case WW_LDATEFMT:
417 format = lc_time->_W_ww_ldatefmt;
418 break;
419
420 case WW_TIMEFMT:
421 default:
422 format = lc_time->_W_ww_timefmt;
423 break;
424 }
425
426 if (lc_time->ww_caltype != 1)
427 {
428 // We have something other than the basic Gregorian calendar
429 bool const is_time_format = field_code == WW_TIMEFMT;
430
431 // We leave the verification of the SYSTEMTIME up to the Windows API
432 // that we call; if one of those functions returns zero to indicate
433 // failure, we fall through and call expand_time() again.
434 SYSTEMTIME system_time;
435 system_time.wYear = static_cast<WORD>(tmptr->tm_year + 1900);
436 system_time.wMonth = static_cast<WORD>(tmptr->tm_mon + 1);
437 system_time.wDay = static_cast<WORD>(tmptr->tm_mday);
438 system_time.wHour = static_cast<WORD>(tmptr->tm_hour);
439 system_time.wMinute = static_cast<WORD>(tmptr->tm_min);
440 system_time.wSecond = static_cast<WORD>(tmptr->tm_sec);
441 system_time.wMilliseconds = 0;
442
443 // Find buffer size required:
444 int cch;
445 if (is_time_format)
446 cch = __acrt_GetTimeFormatEx(lc_time->_W_ww_locale_name, 0, &system_time, format, nullptr, 0);
447 else
448 cch = __acrt_GetDateFormatEx(lc_time->_W_ww_locale_name, 0, &system_time, format, nullptr, 0, nullptr);
449
450 if (cch != 0)
451 {
452 __crt_scoped_stack_ptr<wchar_t> const buffer(_malloca_crt_t(wchar_t, cch));
453 if (buffer.get() != nullptr)
454 {
455 // Do actual date/time formatting:
456 if (is_time_format)
457 cch = __acrt_GetTimeFormatEx(lc_time->_W_ww_locale_name, 0, &system_time, format, buffer.get(), cch);
458 else
459 cch = __acrt_GetDateFormatEx(lc_time->_W_ww_locale_name, 0, &system_time, format, buffer.get(), cch, nullptr);
460
461 // Copy to output buffer:
462 wchar_t const* buffer_it = buffer.get();
463 while (--cch > 0 && *count > 0)
464 {
465 *(*out)++ = *buffer_it++;
466 (*count)--;
467 }
468
469 return true;
470 }
471 }
472
473 // If an error occurs, just fall through to localized Gregorian...
474 }
475
476 while (*format && *count != 0)
477 {
478 wchar_t specifier = 0;
479 bool no_lead_zeros = false;
480
481 // Count the number of repetitions of this character
482 int repeat = 0;
483 wchar_t const* p = format;
484 for (; *p++ == *format; ++repeat);
485 // Leave p pointing to the beginning of the next token
486 p--;
487
488 // Switch on ASCII format character and determine specifier:
489 switch (*format)
490 {
491 case L'M':
492 {
493 switch (repeat)
494 {
495 case 1: no_lead_zeros = true; // fall through
496 case 2: specifier = L'm'; break;
497 case 3: specifier = L'b'; break;
498 case 4: specifier = L'B'; break;
499 }
500 break;
501 }
502
503 case L'd':
504 {
505 switch (repeat)
506 {
507 case 1: no_lead_zeros = true; // fall through
508 case 2: specifier = L'd'; break;
509 case 3: specifier = L'a'; break;
510 case 4: specifier = L'A'; break;
511 }
512 break;
513 }
514
515 case L'y':
516 {
517 switch (repeat)
518 {
519 case 2: specifier = L'y'; break;
520 case 4: specifier = L'Y'; break;
521 }
522 break;
523 }
524
525 case L'h':
526 {
527 switch (repeat)
528 {
529 case 1: no_lead_zeros = true; // fall through
530 case 2: specifier = L'I'; break;
531 }
532 break;
533 }
534
535 case L'H':
536 {
537 switch (repeat)
538 {
539 case 1: no_lead_zeros = true; // fall through
540 case 2: specifier = L'H'; break;
541 }
542 break;
543 }
544
545 case L'm':
546 {
547 switch (repeat)
548 {
549 case 1: no_lead_zeros = true; // fall through
550 case 2: specifier = L'M'; break;
551 }
552 break;
553 }
554
555 case L's': // for compatibility; not strictly WinWord
556 {
557 switch (repeat)
558 {
559 case 1: no_lead_zeros = true; // fall through
560 case 2: specifier = L'S'; break;
561 }
562 break;
563 }
564
565 case L'A':
566 case L'a':
567 {
568 if (!_wcsicmp(format, L"am/pm"))
569 {
570 p = format + 5;
571 }
572 else if (!_wcsicmp(format, L"a/p"))
573 {
574 p = format + 3;
575 }
576
577 specifier = L'p';
578 break;
579 }
580
581 case L't': // t or tt time marker suffix
582 {
583 wchar_t* ampmstr = tmptr->tm_hour <= 11
584 ? lc_time->_W_ampm[0]
585 : lc_time->_W_ampm[1];
586
587 if (repeat == 1 && *count > 0)
588 {
589 *(*out)++ = *ampmstr++;
590 (*count)--;
591 }
592 else
593 {
594 while (*ampmstr != 0 && *count > 0)
595 {
596 *(*out)++ = *ampmstr++;
597 --*count;
598 }
599 }
600 format = p;
601 continue;
602 }
603
604 case L'\'': // literal string
605 {
606 if (repeat % 2 == 0) // even number
607 {
608 format += repeat;
609 }
610 else // odd number
611 {
612 format += repeat;
613 while (*format && *count != 0)
614 {
615 if (*format == L'\'')
616 {
617 format++;
618 break;
619 }
620
621 *(*out)++ = *format++;
622 --*count;
623 }
624 }
625
626 continue;
627 }
628
629 default: // non-control char, print it
630 {
631 break;
632 }
633 }
634
635 // expand specifier, or copy literal if specifier not found
636 if (specifier)
637 {
639
640 format = p; // bump format up to the next token
641 }
642 else
643 {
644 *(*out)++ = *format++;
645 --*count;
646 }
647 }
648
649 return true;
650}
651
652
653
654// Expands the conversion specifier using the time struct and stores the result
655// into the supplied buffer. The expansion is locale-dependent. Returns true
656// on success; false on failure.
658 _locale_t const locale,
659 wchar_t const specifier,
660 tm const* const timeptr,
661 wchar_t** const string,
662 size_t* const left,
663 __crt_lc_time_data const* const lc_time,
664 bool const alternate_form
665 ) throw()
666{
667 switch (specifier)
668 {
669 case L'a': // abbreviated weekday name
670 {
671 _VALIDATE_RETURN(timeptr->tm_wday >= 0 && timeptr->tm_wday <= 6, EINVAL, false);
672 store_string(lc_time->_W_wday_abbr[timeptr->tm_wday], string, left);
673 return true;
674 }
675
676 case L'A': // full weekday name
677 {
678 _VALIDATE_RETURN(timeptr->tm_wday >= 0 && timeptr->tm_wday <= 6, EINVAL, false);
679 store_string(lc_time->_W_wday[timeptr->tm_wday], string, left);
680 return true;
681 }
682
683 case L'b': // abbreviated month name
684 {
685 _VALIDATE_RETURN(timeptr->tm_mon >= 0 && timeptr->tm_mon <= 11, EINVAL, false);
686 store_string(lc_time->_W_month_abbr[timeptr->tm_mon], string, left);
687 return true;
688 }
689
690 case L'B': // full month name
691 {
692 _VALIDATE_RETURN(timeptr->tm_mon >= 0 && timeptr->tm_mon <= 11, EINVAL, false);
693 store_string(lc_time->_W_month[timeptr->tm_mon], string, left);
694 return true;
695 }
696
697 case L'c': // appropriate date and time representation
698 {
699 // In the C locale, %c is equivalent to "%a %b %e %T %Y". This format
700 // is not achievable using the Windows API date and time format APIs
701 // (it's hard to interleave date and time together, and there's no way
702 // to format %e). Therefore, we special case this specifier for the C
703 // locale.
704 if (lc_time == &__lc_time_c && !alternate_form)
705 {
706 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'a', timeptr, string, left, lc_time, false), EINVAL, false);
707 store_string(L" ", string, left);
708 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'b', timeptr, string, left, lc_time, false), EINVAL, false);
709 store_string(L" ", string, left);
710 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'e', timeptr, string, left, lc_time, false), EINVAL, false);
711 store_string(L" ", string, left);
712 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'T', timeptr, string, left, lc_time, false), EINVAL, false);
713 store_string(L" ", string, left);
714 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'Y', timeptr, string, left, lc_time, false), EINVAL, false);
715 }
716 // Otherwise, if we're not in the C locale, use the locale-provided
717 // format strings:
718 else
719 {
720 int const field_code = alternate_form ? WW_LDATEFMT : WW_SDATEFMT;
721
722 _VALIDATE_RETURN_NOEXC(store_winword(locale, field_code, timeptr, string, left, lc_time), EINVAL, false);
723 store_string(L" ", string, left);
724 _VALIDATE_RETURN_NOEXC(store_winword(locale, WW_TIMEFMT, timeptr, string, left, lc_time), EINVAL, false);
725 }
726
727 return true;
728 }
729
730 case L'C': // century in decimal (00-99)
731 {
732 _VALIDATE_RETURN(timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099, EINVAL, false);
733 store_number(__crt_get_century(timeptr->tm_year), 2, string, left, alternate_form ? '\0' : '0');
734 return true;
735 }
736
737 case L'd': // day of the month in decimal (01-31)
738 {
739 _VALIDATE_RETURN(timeptr->tm_mday >= 1 && timeptr->tm_mday <= 31, EINVAL, false);
740 store_number(timeptr->tm_mday, 2, string, left, alternate_form ? '\0' : '0');
741 return true;
742 }
743
744 case L'D': // equivalent to "%m/%d/%y"
745 {
746 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'm', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
747 store_string(L"/", string, left);
748 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'd', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
749 store_string(L"/", string, left);
750 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'y', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
751 return true;
752 }
753
754 case L'e': // day of month as a decimal number (1-31); space padded:
755 {
756 _VALIDATE_RETURN(timeptr->tm_mday >= 1 && timeptr->tm_mday <= 31, EINVAL, false);
757 store_number(timeptr->tm_mday, 2, string, left, alternate_form ? '\0' : ' ');
758 return true;
759 }
760
761 case L'F': // equivalent to "%Y-%m-%d" (ISO 8601):
762 {
763 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'Y', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
764 store_string(L"-", string, left);
765 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'm', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
766 store_string(L"-", string, left);
767 _VALIDATE_RETURN_NOEXC(expand_time(locale, L'd', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
768 return true;
769 }
770
771 case L'g': // last two digits of the week-based year:
772 {
773 _VALIDATE_RETURN(timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099, EINVAL, false);
774 int const iso_year{compute_iso_year(timeptr->tm_year, timeptr->tm_wday, timeptr->tm_yday) + 1900};
775 store_number(iso_year % 100, 2, string, left, '0');
776 return true;
777 }
778
779 case L'G': // week-based year:
780 {
781 _VALIDATE_RETURN(timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099, EINVAL, false);
782 int const iso_year{compute_iso_year(timeptr->tm_year, timeptr->tm_wday, timeptr->tm_yday) + 1900};
783 store_number(iso_year, 4, string, left, '0');
784 return true;
785 }
786
787 case L'h': // equivalent to "%b":
788 {
789 return expand_time(locale, L'b', timeptr, string, left, lc_time, alternate_form);
790 }
791
792 case L'H': // 24-hour decimal (00-23)
793 {
794 _VALIDATE_RETURN(timeptr->tm_hour >= 0 && timeptr->tm_hour <= 23, EINVAL, false);
795 store_number(timeptr->tm_hour, 2, string, left, alternate_form ? '\0' : '0');
796 return true;
797 }
798
799 case L'I': // 12-hour decimal (01-12)
800 {
801 _VALIDATE_RETURN(timeptr->tm_hour >= 0 && timeptr->tm_hour <= 23, EINVAL, false);
802 unsigned hour = timeptr->tm_hour % 12;
803 if (hour == 0)
804 hour = 12;
805
806 store_number(hour, 2, string, left, alternate_form ? '\0' : '0');
807 return true;
808 }
809
810 case L'j': // yday in decimal (001-366)
811 {
812 _VALIDATE_RETURN(timeptr->tm_yday >= 0 && timeptr->tm_yday <= 365, EINVAL, false);
813 store_number(timeptr->tm_yday + 1, 3, string, left, alternate_form ? '\0' : '0');
814 return true;
815 }
816
817 case L'm': // month in decimal (01-12)
818 {
819 _VALIDATE_RETURN(timeptr->tm_mon >= 0 && timeptr->tm_mon <= 11, EINVAL, false);
820 store_number(timeptr->tm_mon + 1, 2, string, left, alternate_form ? '\0' : '0');
821 return true;
822 }
823
824 case L'M': // minute in decimal (00-59)
825 {
826 _VALIDATE_RETURN(timeptr->tm_min >= 0 && timeptr->tm_min <= 59, EINVAL, false);
827 store_number(timeptr->tm_min, 2, string, left, alternate_form ? '\0' : '0');
828 return true;
829 }
830
831 case L'n': // newline character
832 {
833 store_string(L"\n", string, left);
834 return true;
835 }
836
837 case L'p': // AM/PM designation
838 {
839 _VALIDATE_RETURN(timeptr->tm_hour >= 0 && timeptr->tm_hour <= 23, EINVAL, false);
840 wchar_t const* const ampm_string = timeptr->tm_hour <= 11
841 ? lc_time->_W_ampm[0]
842 : lc_time->_W_ampm[1];
843
844 store_string(ampm_string, string, left);
845 return true;
846 }
847
848 case L'r': // Locale-specific 12-hour clock time
849 {
850 // In the C locale, %r is equivalent to "%I:%M:%S %p". This is the only
851 // locale in which we guarantee that %r is a 12-hour time; in all other
852 // locales we only have one time format which may or may not be a 12-hour
853 // format.
854 if (lc_time == &__lc_time_c)
855 {
856 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'I', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
857 store_string(L":", string, left);
858 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'M', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
859 store_string(L":", string, left);
860 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'S', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
861 store_string(L" ", string, left);
862 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'p', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
863 }
864 else
865 {
866 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'X', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
867 }
868
869 return true;
870 }
871
872 case L'R': // Equivalent to "%H:%M"
873 {
874 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'H', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
875 store_string(L":", string, left);
876 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'M', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
877 return true;
878 }
879
880 case L'S': // seconds in decimal (00-60) allowing for a leap second
881 {
882 _VALIDATE_RETURN(timeptr->tm_sec >= 0 && timeptr->tm_sec <= 60, EINVAL, false);
883 store_number(timeptr->tm_sec, 2, string, left, alternate_form ? '\0' : '0');
884 return true;
885 }
886
887 case L't': // tab character
888 {
889 store_string(L"\t", string, left);
890 return true;
891 }
892
893 case L'T': // Equivalent to "%H:%M:%S" (ISO 8601)
894 {
895 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'H', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
896 store_string(L":", string, left);
897 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'M', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
898 store_string(L":", string, left);
899 _VALIDATE_RETURN_NOEXC(expand_time(locale, 'S', timeptr, string, left, lc_time, alternate_form), EINVAL, false);
900 return true;
901 }
902
903 case L'u': // week day in decimal (1-7)
904 case L'w': // week day in decimal (0-6)
905 {
906 _VALIDATE_RETURN(timeptr->tm_wday >= 0 && timeptr->tm_wday <= 6, EINVAL, false);
907
908 int const weekday_number = timeptr->tm_wday == 0 && specifier == L'u'
909 ? 7
910 : timeptr->tm_wday;
911
912 store_number(weekday_number, 1, string, left, alternate_form ? '\0' : '0');
913 return true;
914 }
915
916 case L'U': // sunday week number (00-53)
917 case L'W': // monday week number (00-53)
918 {
919 _VALIDATE_RETURN(timeptr->tm_wday >= 0 && timeptr->tm_wday <= 6, EINVAL, false);
920 int wdaytemp = timeptr->tm_wday;
921 if (specifier == L'W')
922 {
923 if (timeptr->tm_wday == 0) // Monday-based
924 wdaytemp = 6;
925 else
926 wdaytemp = timeptr->tm_wday - 1;
927 }
928
929 _VALIDATE_RETURN(timeptr->tm_yday >= 0 && timeptr->tm_yday <= 365, EINVAL, false);
930 unsigned week_number = 0;
931 if (timeptr->tm_yday >= wdaytemp)
932 {
933 week_number = timeptr->tm_yday / 7;
934 if (timeptr->tm_yday % 7 >= wdaytemp)
935 ++week_number;
936 }
937
938 store_number(week_number, 2, string, left, alternate_form ? '\0' : '0');
939 return true;
940 }
941
942 case L'V': // ISO 8601 week number (01-53):
943 {
945 store_number(iso_week, 2, string, left, alternate_form ? '\0' : '0');
946 return true;
947 }
948
949 case L'x': // date display
950 {
951 int const field_code = alternate_form ? WW_LDATEFMT : WW_SDATEFMT;
952 _VALIDATE_RETURN_NOEXC(store_winword(locale, field_code, timeptr, string, left, lc_time), EINVAL, false);
953 return true;
954 }
955 case L'X': // time display
956 {
957 _VALIDATE_RETURN_NOEXC(store_winword(locale, WW_TIMEFMT, timeptr, string, left, lc_time), EINVAL, false);
958 return true;
959 }
960
961 case L'y': // year without century (00-99)
962 {
963 _VALIDATE_RETURN(timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099, EINVAL, false);
964 unsigned const two_digit_year = __crt_get_2digit_year(timeptr->tm_year);
965 store_number(two_digit_year, 2, string, left, alternate_form ? '\0' : '0');
966 return true;
967 }
968
969 case L'Y': // year with century
970 {
971 _VALIDATE_RETURN(timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099, EINVAL, false);
972 unsigned const full_year = timeptr->tm_year + 1900;
973
974 store_number(full_year, 4, string, left, alternate_form ? '\0' : '0');
975 return true;
976 }
977
978 case L'z': // time zone in ISO 8601 form ("-0430" = 4 hours 30 minutes)
979 {
980 __tzset();
981
982 // Get the current time zone offset from UTC and, if we are currently in
983 // daylight savings time, adjust appropriately:
984 long offset{};
986
987 if (timeptr->tm_isdst)
988 {
989 long dst_bias{};
990 _VALIDATE_RETURN(_get_dstbias(&dst_bias) == 0, EINVAL, false);
991
992 offset += dst_bias;
993 }
994
995 long const positive_offset{offset < 0 ? -offset : offset};
996 long const hours_offset {(positive_offset / 60) / 60};
997 long const minutes_offset{(positive_offset / 60) % 60};
998
999 // This looks wrong, but it is correct: The offset is the difference
1000 // between UTC and the local time zone, so it is a positive value if
1001 // the local time zone is behind UTC.
1002 wchar_t const* const sign_string{offset <= 0 ? L"+" : L"-"};
1003
1004 store_string(sign_string, string, left);
1005 store_number(hours_offset, 2, string, left, '0');
1006 store_number(minutes_offset, 2, string, left, '0');
1007 return true;
1008 }
1009
1010 case L'Z': // time zone name, if any
1011 {
1012 __tzset();
1013 store_string(__wide_tzname()[timeptr->tm_isdst ? 1 : 0], string, left);
1014 return true;
1015 }
1016
1017 case L'%': // percent sign
1018 {
1019 store_string(L"%", string, left);
1020 return true;
1021 }
1022
1023 default: // unknown format directive
1024 {
1025 // We do not raise the invalid parameter handler here. Our caller will
1026 // raise the invalid parameter handler when we return failure.
1027 return false;
1028 }
1029 }
1030
1031 // Unreachable. All switch case statements return.
1032}
1033
1034
1035
1036//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1037//
1038// The _wcsftime family of functions
1039//
1040//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1041// These functions format a time as a string using a given locale. They place
1042// characters into the user's output buffer, expanding time format directives as
1043// described in the provided control string. The lc_time_arg and locale are
1044// used for locale data.
1045//
1046// If the total number of characters that need to be written (including the null
1047// terminator) is less than the max_size, then the number of characters written
1048// (not including the null terminator) is returned. Otherwise, zero is returned.
1049extern "C" size_t __cdecl _Wcsftime_l(
1050 wchar_t* const string,
1051 size_t const max_size,
1052 wchar_t const* const format,
1053 tm const* const timeptr,
1054 void* const lc_time_arg,
1055 _locale_t const locale
1056 )
1057{
1058 _VALIDATE_RETURN(string != nullptr, EINVAL, 0)
1060 *string = L'\0';
1061
1062 _VALIDATE_RETURN(format != nullptr, EINVAL, 0)
1063
1064 _LocaleUpdate locale_update(locale);
1065
1066 __crt_lc_time_data const* const lc_time = lc_time_arg == 0
1067 ? locale_update.GetLocaleT()->locinfo->lc_time_curr
1068 : static_cast<__crt_lc_time_data*>(lc_time_arg);
1069
1070 // Copy the input string to the output string expanding the format
1071 // designations appropriately. Stop copying when one of the following
1072 // is true: (1) we hit a null char in the input stream, or (2) there's
1073 // no room left in the output stream.
1074
1075 wchar_t* string_it = string;
1076 wchar_t const* format_it = format;
1077
1078 bool failed = false;
1079 size_t remaining = max_size;
1080
1081 while (remaining > 0)
1082 {
1083 switch (*format_it)
1084 {
1085 case L'\0':
1086 {
1087 // End of format input string
1088 goto done;
1089 }
1090
1091 case L'%':
1092 {
1093 // Format directive. Take appropriate action based on format control character.
1094 _VALIDATE_RETURN(timeptr != nullptr, EINVAL, 0);
1095
1096 ++format_it; // Skip '%'
1097
1098 // Process flags:
1099 bool alternate_form = false;
1100 if (*format_it == L'#')
1101 {
1102 alternate_form = true;
1103 ++format_it;
1104 }
1105
1106 // Skip ISO E and O alternative representation format modifiers. We
1107 // do not support alternative formats in any locale.
1108 if (*format_it == L'E' || *format_it == L'O')
1109 {
1110 ++format_it;
1111 }
1112
1113 if (!expand_time(locale_update.GetLocaleT(), *format_it, timeptr, &string_it, &remaining, lc_time, alternate_form))
1114 {
1115 // if we don't have any space left, do not set the failure flag:
1116 // we will simply return ERANGE and do not call the invalid
1117 // parameter handler (see below)
1118 if (remaining > 0)
1119 failed = true;
1120
1121 goto done;
1122 }
1123
1124 ++format_it; // Skip format char
1125 break;
1126 }
1127
1128 default:
1129 {
1130 // store character, bump pointers, decrement the char count:
1131 *string_it++ = *format_it++;
1132 --remaining;
1133 break;
1134 }
1135 }
1136 }
1137
1138
1139 // All done. See if we terminated because we hit a null char or because
1140 // we ran out of space:
1141 done:
1142
1143 if (!failed && remaining > 0)
1144 {
1145 // Store a terminating null char and return the number of chars we
1146 // stored in the output string:
1147 *string_it = L'\0';
1148 return max_size - remaining;
1149 }
1150 else
1151 {
1152 // Error: return an empty string:
1153 *string = L'\0';
1154
1155 // Now return our error/insufficient buffer indication:
1156 if (!failed && remaining <= 0)
1157 {
1158 // Do not report this as an error to allow the caller to resize:
1159 errno = ERANGE;
1160 }
1161 else
1162 {
1163 _VALIDATE_RETURN(false, EINVAL, 0);
1164 }
1165
1166 return 0;
1167 }
1168}
1169
1170extern "C" size_t __cdecl _Wcsftime(
1171 wchar_t* const buffer,
1172 size_t const max_size,
1173 wchar_t const* const format,
1174 tm const* const timeptr,
1175 void* const lc_time_arg
1176 )
1177{
1178 return _Wcsftime_l(buffer, max_size, format, timeptr, lc_time_arg, nullptr);
1179}
1180
1181extern "C" size_t __cdecl _wcsftime_l(
1182 wchar_t* const buffer,
1183 size_t const max_size,
1184 wchar_t const* const format,
1185 tm const* const timeptr,
1186 _locale_t const locale
1187 )
1188{
1189 return _Wcsftime_l(buffer, max_size, format, timeptr, nullptr, locale);
1190}
1191
1192extern "C" size_t __cdecl wcsftime(
1193 wchar_t* const buffer,
1194 size_t const max_size,
1195 wchar_t const* const format,
1196 tm const* const timeptr
1197 )
1198{
1199 return _Wcsftime_l(buffer, max_size, format, timeptr, nullptr, nullptr);
1200}
1201
1202
1203
1204/*
1205 * Copyright (c) 1992-2013 by P.J. Plauger. ALL RIGHTS RESERVED.
1206 * Consult your license regarding permissions and restrictions.
1207V6.40:0009 */
#define EINVAL
Definition: acclib.h:90
#define ERANGE
Definition: acclib.h:92
#define __cdecl
Definition: accygwin.h:79
static unsigned char bytes[4]
Definition: adnsresfilter.c:74
static INT max_size
Definition: history.c:51
Definition: _locale.h:75
__crt_lc_time_data const __lc_time_c
Definition: nlsdata.cpp:33
int WINAPI __acrt_GetDateFormatEx(_In_opt_ LPCWSTR locale_name, _In_ DWORD flags, _In_opt_ SYSTEMTIME CONST *date, _In_opt_ LPCWSTR format, _Out_writes_opt_(buffer_count) LPWSTR buffer, _In_opt_ int buffer_count, _In_opt_ LPCWSTR calendar)
#define _ERRCHECK(e)
int WINAPI __acrt_GetTimeFormatEx(_In_opt_ LPCWSTR locale_name, _In_ DWORD flags, _In_opt_ SYSTEMTIME CONST *time, _In_opt_ LPCWSTR format, _Out_writes_opt_(buffer_count) LPWSTR buffer, _In_opt_ int buffer_count)
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
_Check_return_ _Deref_ret_z_ wchar_t **__cdecl __wide_tzname()
Definition: timeset.cpp:185
void __cdecl __tzset()
Definition: tzset.cpp:392
_In_ size_t _In_z_ wchar_t const _In_ tm const _In_opt_ void * lc_time_arg
bool __cdecl __crt_time_is_leap_year(TimeType const yr)
int __crt_get_century(int const year)
int __crt_get_2digit_year(int const year)
_In_ size_t _In_z_ wchar_t const _In_ tm const * timeptr
static const WCHAR month[12][4]
Definition: session.c:2150
unsigned short WORD
Definition: ntddk_ex.h:93
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLdouble n
Definition: glext.h:7729
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
GLintptr offset
Definition: glext.h:5920
GLdouble GLdouble right
Definition: glext.h:10859
GLuint in
Definition: glext.h:9616
GLint left
Definition: glext.h:7726
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLfloat GLfloat p
Definition: glext.h:8902
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define _malloc_crt
#define _VALIDATE_RETURN_NOEXC(expr, errorcode, retexpr)
static const int digits[]
Definition: decode.c:71
#define wcscpy_s(d, l, s)
Definition: utility.h:201
char string[160]
Definition: util.h:11
static DWORD DWORD void LPSTR DWORD cch
Definition: str.c:202
static char * dest
Definition: rtl.c:135
#define _Inout_
Definition: no_sal2.h:162
#define _Success_(c)
Definition: no_sal2.h:84
#define _In_reads_or_z_(s)
Definition: no_sal2.h:174
#define L(x)
Definition: ntvdm.h:50
static calc_node_t temp
Definition: rpn_ieee.c:38
#define errno
Definition: errno.h:18
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_CRTIMP errno_t __cdecl _get_dstbias(_Out_ long *_Daylight_savings_bias)
_CRTIMP errno_t __cdecl _get_timezone(_Out_ long *_Timezone)
#define memset(x, y, z)
Definition: compat.h:39
WORD wYear
Definition: winbase.h:930
WORD wMilliseconds
Definition: winbase.h:937
WORD wMonth
Definition: winbase.h:931
WORD wHour
Definition: winbase.h:934
WORD wSecond
Definition: winbase.h:936
WORD wMinute
Definition: winbase.h:935
WORD wDay
Definition: winbase.h:933
wchar_t * _W_month[12]
wchar_t * _W_month_abbr[12]
wchar_t * _W_wday_abbr[7]
Definition: format.c:58
Definition: time.h:68
int tm_mon
Definition: time.h:73
int tm_year
Definition: time.h:74
int tm_hour
Definition: time.h:71
int tm_sec
Definition: time.h:69
int tm_isdst
Definition: time.h:77
int tm_yday
Definition: time.h:76
int tm_mday
Definition: time.h:72
int tm_min
Definition: time.h:70
int tm_wday
Definition: time.h:75
Definition: pdh_main.c:94
#define _CrtWcstime_Writes_and_advances_ptr_(count)
Definition: wcsftime.cpp:184
@ tuesday
Definition: wcsftime.cpp:313
@ saturday
Definition: wcsftime.cpp:317
@ thursday
Definition: wcsftime.cpp:315
@ friday
Definition: wcsftime.cpp:316
@ sunday
Definition: wcsftime.cpp:311
@ monday
Definition: wcsftime.cpp:312
@ wednesday
Definition: wcsftime.cpp:314
static void __cdecl store_string(_In_reads_or_z_(*count) wchar_t const *in, _CrtWcstime_Writes_and_advances_ptr_(*count) wchar_t **const out, _Inout_ size_t *const count)
Definition: wcsftime.cpp:193
static int __cdecl compute_iso_year(int const year, int const wday, int const yday)
Definition: wcsftime.cpp:362
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t _Inout_ size_t __crt_lc_time_data const bool alternate_form throw()
Definition: wcsftime.cpp:407
wchar_t *__cdecl _W_Getmonths()
Definition: wcsftime.cpp:51
wchar_t specifier
Definition: wcsftime.cpp:381
#define PROCESS_NARROW_STRING(STR)
size_t __cdecl _Wcsftime_l(wchar_t *const string, size_t const max_size, wchar_t const *const format, tm const *const timeptr, void *const lc_time_arg, _locale_t const locale)
Definition: wcsftime.cpp:1049
wchar_t tm const * tmptr
Definition: wcsftime.cpp:382
size_t __cdecl _wcsftime_l(wchar_t *const buffer, size_t const max_size, wchar_t const *const format, tm const *const timeptr, _locale_t const locale)
Definition: wcsftime.cpp:1181
static void __cdecl store_number(int value, int digits, _CrtWcstime_Writes_and_advances_ptr_(*count) wchar_t **const out, _Inout_ size_t *const count, wchar_t const pad_character)
Definition: wcsftime.cpp:261
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
#define WW_SDATEFMT
Definition: wcsftime.cpp:179
#define WW_TIMEFMT
Definition: wcsftime.cpp:181
static int compute_week_of_year(int const wstart, int const wday, int const yday)
Definition: wcsftime.cpp:320
wchar_t *__cdecl _W_Getdays()
Definition: wcsftime.cpp:19
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t _Inout_ size_t * count
Definition: wcsftime.cpp:384
static int __cdecl compute_iso_week(int const year, int const wday, int const yday)
Definition: wcsftime.cpp:349
static bool __cdecl expand_time(_locale_t const locale, wchar_t const specifier, tm const *const timeptr, wchar_t **const string, size_t *const left, __crt_lc_time_data const *const lc_time, bool const alternate_form)
Definition: wcsftime.cpp:657
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t _Inout_ size_t __crt_lc_time_data const * lc_time
Definition: wcsftime.cpp:385
#define WW_LDATEFMT
Definition: wcsftime.cpp:180
#define PROCESS_NARROW_ARRAY(ARR)
#define PROCESS_WIDE_STRING(STR)
void *__cdecl _W_Gettnames()
Definition: wcsftime.cpp:83
size_t __cdecl wcsftime(wchar_t *const buffer, size_t const max_size, wchar_t const *const format, tm const *const timeptr)
Definition: wcsftime.cpp:1192
int const field_code
Definition: wcsftime.cpp:402
size_t __cdecl _Wcsftime(wchar_t *const buffer, size_t const max_size, wchar_t const *const format, tm const *const timeptr, void *const lc_time_arg)
Definition: wcsftime.cpp:1170
static void __cdecl store_number_without_lead_zeroes(int value, _CrtWcstime_Writes_and_advances_ptr_(*count) wchar_t **const out, _Inout_ size_t *const count)
Definition: wcsftime.cpp:214
#define PROCESS_WIDE_ARRAY(ARR)
static int __cdecl compute_iso_week_internal(int year, int wday, int yday)
Definition: wcsftime.cpp:326
static int repeat
Definition: xmllint.c:137