[PATCH v2 4/5] ucrtbase: Correct behavior of strftime format %X.
Jeff Smith
whydoubt at gmail.com
Mon Nov 18 01:07:29 CST 2019
Signed-off-by: Jeff Smith <whydoubt at gmail.com>
---
dlls/msvcrt/time.c | 86 ++++++++++++++++++--------------------
dlls/ucrtbase/tests/misc.c | 2 +-
2 files changed, 42 insertions(+), 46 deletions(-)
diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c
index 058a8a53c9..30f59e0846 100644
--- a/dlls/msvcrt/time.c
+++ b/dlls/msvcrt/time.c
@@ -54,6 +54,12 @@ static const int MonthLengths[2][12] =
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
+#if _MSVCR_VER>=140
+static const int MAX_SECONDS = 60;
+#else
+static const int MAX_SECONDS = 59;
+#endif
+
static inline BOOL IsLeapYear(int Year)
{
return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
@@ -954,45 +960,6 @@ char ** CDECL __p__tzname(void)
return MSVCRT__tzname;
}
-static inline BOOL strftime_time(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max,
- const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data)
-{
- SYSTEMTIME st;
- MSVCRT_size_t ret;
- LCID lcid;
-
- st.wYear = mstm->tm_year + 1900;
- st.wMonth = mstm->tm_mon + 1;
- st.wDayOfWeek = mstm->tm_wday;
- st.wDay = mstm->tm_mday;
- st.wHour = mstm->tm_hour;
- st.wMinute = mstm->tm_min;
- st.wSecond = mstm->tm_sec;
- st.wMilliseconds = 0;
-
-#if _MSVCR_VER < 110
- lcid = time_data->lcid;
-#else
- lcid = LocaleNameToLCID(time_data->locname, 0);
-#endif
-
- ret = GetTimeFormatA(lcid, 0, &st, time_data->str.names.time, NULL, 0);
- if(ret && ret<max-*pos)
- ret = GetTimeFormatA(lcid, 0, &st, time_data->str.names.time,
- str+*pos, max-*pos);
- if(!ret) {
- *str = 0;
- *MSVCRT__errno() = MSVCRT_EINVAL;
- return FALSE;
- }else if(ret > max-*pos) {
- *str = 0;
- *MSVCRT__errno() = MSVCRT_ERANGE;
- return FALSE;
- }
- *pos += ret-1;
- return TRUE;
-}
-
static inline BOOL strftime_tzdiff(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max, BOOL is_dst)
{
MSVCRT_long tz = MSVCRT___timezone + (is_dst ? MSVCRT__dstbias : 0);
@@ -1117,10 +1084,39 @@ static inline BOOL strftime_format(char *str, MSVCRT_size_t *pos, MSVCRT_size_t
while(*format == *substr) format++;
/* TODO: era */
break;
+ case 'h':
+ while(*format == *substr) format++;
+ if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
+ goto einval_error;
+ ret = strftime_int(str, pos, max, (mstm->tm_hour + 11) % 12 + 1,
+ (format - substr < 2) ? 0 : 2, 1, 12);
+ break;
+ case 'H':
+ while(*format == *substr) format++;
+ ret = strftime_int(str, pos, max, mstm->tm_hour, (format - substr < 2) ? 0 : 2, 0, 23);
+ break;
+ case 'm':
+ while(*format == *substr) format++;
+ ret = strftime_int(str, pos, max, mstm->tm_min, (format - substr < 2) ? 0 : 2, 0, 59);
+ break;
+ case 's':
+ while(*format == *substr) format++;
+ ret = strftime_int(str, pos, max, mstm->tm_sec,
+ (format - substr < 2) ? 0 : 2, 0, MAX_SECONDS);
+ break;
+ case 't':
+ while(*format == *substr) format++;
+ if(!MSVCRT_CHECK_PMT(mstm->tm_hour>=0 && mstm->tm_hour<=23))
+ goto einval_error;
+ ret = strftime_nstr(str, pos, max,
+ (mstm->tm_hour < 12) ? time_data->str.names.am : time_data->str.names.pm,
+ (format - substr < 2) ? 1 : MSVCRT_SIZE_MAX);
+ break;
default:
while(*format && *format != '\'' &&
- *format != 'd' && *format != 'M' &&
- *format != 'y' && *format != 'g')
+ *format != 'd' && *format != 'M' && *format != 'y' &&
+ *format != 'g' && *format != 'h' && *format != 'H' &&
+ *format != 'm' && *format != 's' && *format != 't')
format++;
ret = strftime_nstr(str, pos, max, substr, format - substr);
break;
@@ -1182,7 +1178,7 @@ static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *f
return 0;
if(ret < max)
str[ret++] = ' ';
- if(!strftime_time(str, &ret, max, mstm, time_data))
+ if(!strftime_format(str, &ret, max, mstm, time_data, time_data->str.names.time))
return 0;
break;
case 'x':
@@ -1191,7 +1187,7 @@ static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *f
return 0;
break;
case 'X':
- if(!strftime_time(str, &ret, max, mstm, time_data))
+ if(!strftime_format(str, &ret, max, mstm, time_data, time_data->str.names.time))
return 0;
break;
case 'a':
@@ -1329,7 +1325,7 @@ static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *f
break;
#endif
case 'S':
- if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, 59))
+ if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
return 0;
break;
#if _MSVCR_VER>=140
@@ -1345,7 +1341,7 @@ static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *f
return 0;
if(ret < max)
str[ret++] = ':';
- if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, 59))
+ if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, MAX_SECONDS))
return 0;
break;
case 'u':
diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c
index 35b7375cd8..3aca31734f 100644
--- a/dlls/ucrtbase/tests/misc.c
+++ b/dlls/ucrtbase/tests/misc.c
@@ -946,7 +946,7 @@ static void test_strftime(void)
{"%#x", "Thursday, February 30, 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
{"%X", "00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
{"%X", "14:00:00", { 0, 0, 14, 1, 0, 70, 4, 0, 0 }},
- {"%X", "23:59:60", { 60, 59, 23, 1, 0, 70, 4, 0, 0 }, TRUE},
+ {"%X", "23:59:60", { 60, 59, 23, 1, 0, 70, 4, 0, 0 }},
};
const struct tm epoch = { 0, 0, 0, 1, 0, 70, 4, 0, 0 };
--
2.23.0
More information about the wine-devel
mailing list