Signed-off-by: Jeff Smith whydoubt@gmail.com --- dlls/msvcrt/tests/time.c | 8 +-- dlls/msvcrt/time.c | 131 ++++++++++++++++++++++++------------- dlls/ucrtbase/tests/misc.c | 6 +- 3 files changed, 94 insertions(+), 51 deletions(-)
diff --git a/dlls/msvcrt/tests/time.c b/dlls/msvcrt/tests/time.c index 4a3d81d2dd..a71c3efee2 100644 --- a/dlls/msvcrt/tests/time.c +++ b/dlls/msvcrt/tests/time.c @@ -611,13 +611,13 @@ static void test_strftime(void) } tests[] = { {"e%#%e", "e%e", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, {"%c", "01/01/70 00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, - {"%c", "02/30/70 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }, TRUE}, + {"%c", "02/30/70 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }}, {"%#c", "Thursday, January 01, 1970 00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, - {"%#c", "Thursday, February 30, 1970 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }, TRUE}, + {"%#c", "Thursday, February 30, 1970 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }}, {"%x", "01/01/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, - {"%x", "02/30/70", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }, TRUE}, + {"%x", "02/30/70", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }}, {"%#x", "Thursday, January 01, 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, - {"%#x", "Thursday, February 30, 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }, TRUE}, + {"%#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 }}, {"%a", "Thu", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c index ae6fcc8b7a..058a8a53c9 100644 --- a/dlls/msvcrt/time.c +++ b/dlls/msvcrt/time.c @@ -954,46 +954,6 @@ char ** CDECL __p__tzname(void) return MSVCRT__tzname; }
-static inline BOOL strftime_date(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max, - BOOL alternate, const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data) -{ - char *format; - 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 - - format = alternate ? time_data->str.names.date : time_data->str.names.short_date; - ret = GetDateFormatA(lcid, 0, &st, format, NULL, 0); - if(ret && ret<max-*pos) - ret = GetDateFormatA(lcid, 0, &st, format, 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_time(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max, const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data) { @@ -1057,9 +1017,12 @@ static inline BOOL strftime_tzdiff(char *str, MSVCRT_size_t *pos, MSVCRT_size_t return TRUE; }
-static inline BOOL strftime_str(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max, char *src) +#define strftime_str(a,b,c,d) strftime_nstr(a,b,c,d,MSVCRT_SIZE_MAX) +static inline BOOL strftime_nstr(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max, + const char *src, MSVCRT_size_t len) { - MSVCRT_size_t len = strlen(src); + if(len == MSVCRT_SIZE_MAX) + len = strlen(src); if(len > max-*pos) { *str = 0; *MSVCRT__errno() = MSVCRT_ERANGE; @@ -1093,6 +1056,84 @@ static inline BOOL strftime_int(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max return TRUE; }
+static inline BOOL strftime_format(char *str, MSVCRT_size_t *pos, MSVCRT_size_t max, + const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data, const char *format) +{ + BOOL ret = TRUE; + + while(*format && ret) + { + const char *substr = format++; + switch(*substr) { + case ''': + while(*format && *format != ''') format++; + substr++; + ret = strftime_nstr(str, pos, max, substr, (*substr == ''') ? 1 : format - substr); + if(ret && *format == ''') + format++; + break; + case 'd': + while(*format == *substr) format++; + if(format - substr < 3) + ret = strftime_int(str, pos, max, mstm->tm_mday, (format - substr < 2) ? 0 : 2, 0, 31); + else { + if(!MSVCRT_CHECK_PMT(mstm->tm_wday>=0 && mstm->tm_wday<=6)) + goto einval_error; + if(format - substr == 3) + ret = strftime_str(str, pos, max, time_data->str.names.short_wday[mstm->tm_wday]); + else + ret = strftime_str(str, pos, max, time_data->str.names.wday[mstm->tm_wday]); + } + break; + case 'M': + while(*format == *substr) format++; + if(format - substr < 3) + ret = strftime_int(str, pos, max, mstm->tm_mon+1, (format - substr < 2) ? 0 : 2, 1, 12); + else { + if(!MSVCRT_CHECK_PMT(mstm->tm_mon>=0 && mstm->tm_mon<=11)) + goto einval_error; + if(format - substr == 3) + ret = strftime_str(str, pos, max, time_data->str.names.short_mon[mstm->tm_mon]); + else + ret = strftime_str(str, pos, max, time_data->str.names.mon[mstm->tm_mon]); + } + break; + case 'y': + while(*format == *substr) format++; + if(format - substr < 3) { + int year = mstm->tm_year + 1900; +#if _MSVCR_VER>=140 + if(!MSVCRT_CHECK_PMT(year>=0 && year<=9999)) + goto einval_error; +#else + if(!MSVCRT_CHECK_PMT(year>=1900)) + goto einval_error; +#endif + ret = strftime_int(str, pos, max, year%100, 2, 0, 99); + } else + ret = strftime_int(str, pos, max, mstm->tm_year+1900, 4, 0, 9999); + break; + case 'g': + while(*format == *substr) format++; + /* TODO: era */ + break; + default: + while(*format && *format != ''' && + *format != 'd' && *format != 'M' && + *format != 'y' && *format != 'g') + format++; + ret = strftime_nstr(str, pos, max, substr, format - substr); + break; + } + } + + return ret; + +einval_error: + *str = 0; + return FALSE; +} + static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *format, const struct MSVCRT_tm *mstm, MSVCRT___lc_time_data *time_data, MSVCRT__locale_t loc) { @@ -1136,7 +1177,8 @@ static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *f
switch(*format) { case 'c': - if(!strftime_date(str, &ret, max, alternate, mstm, time_data)) + if(!strftime_format(str, &ret, max, mstm, time_data, + alternate ? time_data->str.names.date : time_data->str.names.short_date)) return 0; if(ret < max) str[ret++] = ' '; @@ -1144,7 +1186,8 @@ static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *f return 0; break; case 'x': - if(!strftime_date(str, &ret, max, alternate, mstm, time_data)) + if(!strftime_format(str, &ret, max, mstm, time_data, + alternate ? time_data->str.names.date : time_data->str.names.short_date)) return 0; break; case 'X': diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c index fa5f29372c..35b7375cd8 100644 --- a/dlls/ucrtbase/tests/misc.c +++ b/dlls/ucrtbase/tests/misc.c @@ -939,11 +939,11 @@ static void test_strftime(void) {"%c", "Thu Jan 1 00:00:00 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }, TRUE}, {"%c", "Thu Feb 30 00:00:00 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }, TRUE}, {"%#c", "Thursday, January 01, 1970 00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, - {"%#c", "Thursday, February 30, 1970 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }, TRUE}, + {"%#c", "Thursday, February 30, 1970 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }}, {"%x", "01/01/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, - {"%x", "02/30/70", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }, TRUE}, + {"%x", "02/30/70", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }}, {"%#x", "Thursday, January 01, 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, - {"%#x", "Thursday, February 30, 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }, TRUE}, + {"%#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},