<div dir="ltr"><div>I've been working on this patch for a few days now to fulfill my bug report (#47809). However, every time I've gone to try to submit it somebody has proposed a commit that I can't see. So, I know that this patch is already outdated but I wanted to drop it here for the record.</div><div><br></div><div>Some notes on this patch:</div><div>* I know it's not as trivial as most of the other stuff going on this file. Sorry about that, but I couldn't think of a cleaner way to do it. I don't think I did anything unorthodox as far as code calls, but I packaged all the ISO 8601 stuff in a block with its own variables to keep it self-contained.</div><div>* This is my first Wine patch (and only my second ever software patch) so if you have some constructive criticism, I'm all for it.</div><div><br></div>From a5e1742f944a5c857283b33653265a8d702b06fc Mon Sep 17 00:00:00 2001<br>From: Chuck Ricketts <<a href="mailto:chuck.the.pc.guy%2Bwinehq@gmail.com">chuck.the.pc.guy+winehq@gmail.com</a>><br>Date: Tue, 1 Oct 2019 01:28:07 -0500<br>Subject: [PATCH] msvcrt: add missing tokens in strftime_helper (except %r)<br><br>---<br> dlls/msvcrt/time.c | 264 +++++++++++++++++++++++++++++++++++++++++++++<br> 1 file changed, 264 insertions(+)<br><br>diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c<br>index c72b3ed21e..cfe1463996 100644<br>--- a/dlls/msvcrt/time.c<br>+++ b/dlls/msvcrt/time.c<br>@@ -1141,6 +1141,7 @@ static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *f<br>             if(!strftime_str(str, &ret, max, time_data->str.names.wday[mstm->tm_wday]))<br>                 return 0;<br>             break;<br>+        case 'h':<br>         case 'b':<br>             if(mstm->tm_mon<0 || mstm->tm_mon>11)<br>                 goto einval_error;<br>@@ -1153,10 +1154,142 @@ static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *f<br>             if(!strftime_str(str, &ret, max, time_data->str.names.mon[mstm->tm_mon]))<br>                 return 0;<br>             break;<br>+        case 'C':<br>+            if(!strftime_int(str, &ret, max, (mstm->tm_year+1900)/100, alternate ? 0: 2, 0, 99))<br>+                return 0;<br>+            break;<br>         case 'd':<br>             if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 0, 31))<br>                 return 0;<br>             break;<br>+        case 'D':<br>+            {<br>+                char* tmp_str = 0;<br>+<br>+                if(mstm->tm_mon<0 || mstm->tm_mon>11)<br>+                    goto einval_error;<br>+                if(mstm->tm_mday<1 || mstm->tm_mday>31)<br>+                    goto einval_error;<br>+<br>+                if(!(tmp_str == MSVCRT_malloc(9)))<br>+                    return 0;<br>+                MSVCRT__snprintf(tmp_str, 9, "%0*d/%0*d/%0*d", 2, mstm->tm_mon, 2, mstm->tm_mday,<br>+                                     2, (mstm->tm_year+1900)%100);<br>+                if(!strftime_str(str, &ret, max, tmp_str)) {<br>+                    MSVCRT_free(tmp_str);<br>+                    return 0;<br>+                }<br>+                MSVCRT_free(tmp_str);<br>+            }<br>+            break;<br>+        case 'e':<br>+            if(mstm->tm_mday<1 || mstm->tm_mday>31)<br>+                goto einval_error;<br>+            if(!strftime_int(str, &ret, max, mstm->tm_mday, 2, 1, 31))<br>+                return 0;<br>+            if(str[ret-2] == '0')<br>+                str[ret-2] = ' ';<br>+            break;<br>+        case 'F':<br>+            {<br>+                char* tmp_str = 0;<br>+<br>+                if(mstm->tm_mon<0 || mstm->tm_mon>11)<br>+                    goto einval_error;<br>+                if(mstm->tm_mday<1 || mstm->tm_mday>31)<br>+                    goto einval_error;<br>+<br>+                if(!(tmp_str = MSVCRT_malloc(12)))<br>+                    return 0;<br>+<br>+                MSVCRT__snprintf(tmp_str, 12, "%d-%0*d-%0*d", mstm->tm_year+1900, 2,<br>+                                     mstm->tm_mon+1, 2, mstm->tm_mday);<br>+                if(!strftime_str(str, &ret, max, tmp_str)) {<br>+                    MSVCRT_free(tmp_str);<br>+                    return 0;<br>+                }<br>+                MSVCRT_free(tmp_str);<br>+            }<br>+            break;<br>+        case 'G':<br>+            {<br>+#ifdef _WIN64<br>+                MSVCRT___time64_t firstmontime = 0;<br>+                MSVCRT___time64_t temp_time = 0;<br>+#else<br>+                MSVCRT___time32_t firstmontime = 0;<br>+                MSVCRT___time32_t temp_time = 0;<br>+#endif<br>+                struct MSVCRT_tm* tmp_mstm = 0;<br>+                struct MSVCRT_tm* oldstate = 0;<br>+                struct MSVCRT_tm* firstmontm = 0;<br>+                int iso8601yr = -1;<br>+                int iso8601wk = -1;<br>+                char* tmp_str = 0;<br>+<br>+                if(!(tmp_mstm = MSVCRT_malloc(sizeof(struct MSVCRT_tm))))<br>+                  return 0;<br>+                if(msvcrt_get_thread_data()->time_buffer &&<br>+                       !(oldstate = MSVCRT_malloc(sizeof(struct MSVCRT_tm)))) {<br>+                  MSVCRT_free(tmp_mstm);<br>+                  return 0;<br>+                }<br>+<br>+                if(oldstate)<br>+                    memcpy(oldstate, msvcrt_get_thread_data()->time_buffer,<br>+                               sizeof(struct MSVCRT_tm));<br>+<br>+                memcpy(tmp_mstm, mstm, sizeof(struct MSVCRT_tm));<br>+<br>+                temp_time = MSVCRT_mktime(tmp_mstm);<br>+                MSVCRT_free(tmp_mstm);<br>+                tmp_mstm = MSVCRT_gmtime(&temp_time);<br>+<br>+                iso8601yr = tmp_mstm->tm_year + 1900;<br>+                iso8601wk = (tmp_mstm->tm_yday+1-(tmp_mstm->tm_wday==0?7:tmp_mstm->tm_wday)+10)/7;<br>+                if(iso8601wk == 53) {<br>+                   if(!(firstmontm = MSVCRT_malloc(sizeof(struct MSVCRT_tm)))) {<br>+                       MSVCRT_free(oldstate);<br>+                       return 0;<br>+                   }<br>+                   memset(firstmontm, '\0', sizeof(struct MSVCRT_tm));<br>+                   firstmontm->tm_mon = 0;<br>+                   firstmontm->tm_mday = 4;<br>+                   firstmontm->tm_year = tmp_mstm->tm_year+1;<br>+                   firstmontime = MSVCRT_mktime(firstmontm);<br>+                   MSVCRT_free(firstmontm);<br>+                   firstmontm = MSVCRT_gmtime(&firstmontime);<br>+                   firstmontime = firstmontime-((firstmontm->tm_wday-1==-1?6:firstmontm->tm_wday-1)*86400);<br>+                   if(firstmontime <= temp_time)<br>+                      iso8601yr += 1;<br>+                }<br>+                if(iso8601wk == 0)<br>+                  iso8601yr -= 1;<br>+<br>+                if(!(tmp_str = MSVCRT_malloc(6))) {<br>+                    MSVCRT_free(oldstate);<br>+                    return 0;<br>+                }<br>+                memset(tmp_str, '\0', 6);<br>+<br>+                MSVCRT__snprintf(tmp_str, 6, "%d", iso8601yr);<br>+                if(!strftime_str(str, &ret, max, tmp_str)) {<br>+                    if(oldstate) {<br>+                        memcpy(msvcrt_get_thread_data()->time_buffer, oldstate,<br>+                                   sizeof(struct MSVCRT_tm));<br>+                        MSVCRT_free(oldstate);<br>+                    }<br>+                    MSVCRT_free(tmp_str);<br>+                    return 0;<br>+                }<br>+                if(oldstate) {<br>+                    memcpy(msvcrt_get_thread_data()->time_buffer, oldstate,<br>+                               sizeof(struct MSVCRT_tm));<br>+                    MSVCRT_free(oldstate);<br>+                }<br>+                MSVCRT_free(tmp_str);<br>+            }<br>+            break;<br>         case 'H':<br>             if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))<br>                 return 0;<br>@@ -1217,6 +1350,137 @@ static MSVCRT_size_t strftime_helper(char *str, MSVCRT_size_t max, const char *f<br>                 return 0;<br>             break;<br> #endif<br>+        case 'u':<br>+            {<br>+#ifdef _WIN64<br>+                MSVCRT___time64_t tmp_time = 0;<br>+#else<br>+                MSVCRT___time32_t tmp_time = 0;<br>+#endif<br>+                struct MSVCRT_tm* tmp_mstm = 0;<br>+                struct MSVCRT_tm* oldstate = 0;<br>+<br>+                if(!(tmp_mstm = MSVCRT_malloc(sizeof(struct MSVCRT_tm))))<br>+                    return 0;<br>+                if( msvcrt_get_thread_data()->time_buffer &&<br>+                       !(oldstate = MSVCRT_malloc(sizeof(struct MSVCRT_tm)))) {<br>+                    MSVCRT_free(tmp_mstm);<br>+                    return 0;<br>+                }<br>+<br>+                if( oldstate )<br>+                    memcpy(oldstate, msvcrt_get_thread_data()->time_buffer,<br>+                               sizeof(struct MSVCRT_tm));<br>+                memcpy(tmp_mstm, mstm, sizeof(struct MSVCRT_tm));<br>+<br>+                tmp_time = MSVCRT_mktime(tmp_mstm);<br>+                MSVCRT_free(tmp_mstm);<br>+                tmp_mstm = MSVCRT_gmtime(&tmp_time);<br>+<br>+                if(!strftime_int(str, &ret, max, (tmp_mstm->tm_wday-1==-1?6:tmp_mstm->tm_wday-1)+1,<br>+                                     0, 1, 7)) {<br>+                    if( oldstate ) {<br>+                        memcpy(msvcrt_get_thread_data()->time_buffer, oldstate,<br>+                                   sizeof(struct MSVCRT_tm));<br>+                        MSVCRT_free(oldstate);<br>+                    }<br>+                    return 0;<br>+                }<br>+<br>+                if( oldstate ) {<br>+                    memcpy(msvcrt_get_thread_data()->time_buffer, oldstate,<br>+                               sizeof(struct MSVCRT_tm));<br>+                    MSVCRT_free(oldstate);<br>+                }<br>+            }<br>+            break;<br>+        case 'V':<br>+            {<br>+#ifdef _WIN64<br>+                MSVCRT___time64_t tmp_time = 0;<br>+                MSVCRT___time64_t tmp_time_mon = 0;<br>+#else<br>+                MSVCRT___time32_t tmp_time = 0;<br>+                MSVCRT___time32_t tmp_time_mon = 0;<br>+#endif<br>+                int iso8601wk;<br>+<br>+                struct MSVCRT_tm* tmp_mstm = 0;<br>+                struct MSVCRT_tm* oldstate = 0;<br>+<br>+                if(!(tmp_mstm = MSVCRT_malloc(sizeof(struct MSVCRT_tm))))<br>+                    return 0;<br>+                if(msvcrt_get_thread_data()->time_buffer &&<br>+                       !(oldstate = MSVCRT_malloc(sizeof(struct MSVCRT_tm)))) {<br>+                    MSVCRT_free(tmp_mstm);<br>+                    return 0;<br>+                }<br>+<br>+                if( oldstate )<br>+                    memcpy(oldstate, msvcrt_get_thread_data()->time_buffer,<br>+                               sizeof(struct MSVCRT_tm));<br>+<br>+                memcpy(tmp_mstm, mstm, sizeof(struct MSVCRT_tm));<br>+<br>+                tmp_time = MSVCRT_mktime(tmp_mstm);<br>+                MSVCRT_free(tmp_mstm);<br>+                tmp_mstm = MSVCRT_gmtime(&tmp_time);<br>+<br>+                iso8601wk = ((tmp_mstm->tm_yday+1-(tmp_mstm->tm_wday==0?7:tmp_mstm->tm_wday)+10)/7);<br>+                if (iso8601wk == 53 ) {<br>+                    if(!(tmp_mstm = MSVCRT_malloc(sizeof(struct MSVCRT_tm)))) {<br>+                        if(oldstate)<br>+                            MSVCRT_free(oldstate);<br>+                        return 0;<br>+                    }<br>+<br>+                    memset(tmp_mstm, '\0', sizeof(struct MSVCRT_tm));<br>+<br>+                    tmp_mstm->tm_mday = 4;<br>+                    tmp_mstm->tm_mon = 0;<br>+                    tmp_mstm->tm_year = (mstm->tm_year+1);<br>+                    tmp_time_mon = MSVCRT_mktime(tmp_mstm);<br>+                    MSVCRT_free(tmp_mstm);<br>+                    tmp_time_mon = tmp_time_mon-((tmp_mstm->tm_wday-1==-1?6:tmp_mstm->tm_wday-1)*86400);<br>+                    if(tmp_time_mon <= tmp_time)<br>+                        iso8601wk = 1;<br>+                    else<br>+                        iso8601wk = 53;<br>+                }<br>+                if(iso8601wk == 0) {<br>+                    if(!(tmp_mstm = MSVCRT_malloc(sizeof(struct MSVCRT_tm)))) {<br>+                        if(oldstate)<br>+                            MSVCRT_free(oldstate);<br>+                        return 0;<br>+                    }<br>+<br>+                    memset(tmp_mstm, '\0', sizeof(struct MSVCRT_tm));<br>+<br>+                    tmp_mstm->tm_mday = 4;<br>+                    tmp_mstm->tm_mon = 0;<br>+                    tmp_mstm->tm_year = mstm->tm_year;<br>+                    tmp_time_mon = MSVCRT_mktime(tmp_mstm);<br>+                    tmp_time_mon = (tmp_time_mon-((tmp_mstm->tm_wday-1==-1?6:tmp_mstm->tm_wday-1)*86400))-604800;<br>+                    MSVCRT_free(tmp_mstm);<br>+                    tmp_mstm = MSVCRT_gmtime(&tmp_time_mon);<br>+                    iso8601wk = (tmp_mstm->tm_yday+1-(tmp_mstm->tm_wday==0?7:tmp_mstm->tm_wday)+10)/7;<br>+                }<br>+<br>+                if(!strftime_int(str, &ret, max, iso8601wk, 2, 0, 53)) {<br>+                    if( oldstate ) {<br>+                        memcpy(msvcrt_get_thread_data()->time_buffer, oldstate,<br>+                                   sizeof(struct MSVCRT_tm));<br>+                        MSVCRT_free(oldstate);<br>+                    }<br>+                    return 0;<br>+                }<br>+                if( oldstate ) {<br>+                    memcpy(msvcrt_get_thread_data()->time_buffer, oldstate,<br>+                               sizeof(struct MSVCRT_tm));<br>+                    MSVCRT_free(oldstate);<br>+                }<br>+            }<br>+            break;<br>         case 'w':<br>             if(!strftime_int(str, &ret, max, mstm->tm_wday, 0, 0, 6))<br>                 return 0;<br>-- <br>2.17.1<br></div>