WinCE strftime work in progress WINCE_NSPRPUB_RELEASE_4_2_BETA1
authorblythe%netscape.com
Mon, 11 Feb 2002 23:46:05 +0000
branchWINCE_NSPRPUB_RELEASE_4_2_BETA1
changeset 2247 002aa6ae8bbf032e04e7f2fcf37fa09b996376ac
parent 2239 9b3cf2f0c750383f82cdf2eda4f27f413ff86bad
child 2248 b7534a503b4674f73eb3507a89eb4a987293d3d1
push idunknown
push userunknown
push dateunknown
WinCE strftime work in progress
pr/include/md/_win32_unicode.h
pr/include/md/_wince.h
pr/src/md/windows/w32time.c
pr/src/md/windows/w32unicode.c
pr/src/md/windows/w95io.c
--- a/pr/include/md/_win32_unicode.h
+++ b/pr/include/md/_win32_unicode.h
@@ -54,16 +54,27 @@ LPWSTR _PR_MD_MALLOC_A2W(LPCSTR inString
  * Non-mallocing/faster version to return a wide char string based on the
  *  ANSI (multi byte, ansi code page) string passed in.
  *
  * NOTE:  inWideStringChars is number of wide characters in outWideString,
  *          NOT the number of bytes....
  */
 LPWSTR _PR_MD_A2W(LPCSTR inString, LPWSTR outWideString, int inWideStringChars);
 
+/*
+ * _PR_MD_W2A
+ *
+ * Non-mallocing fucntion to return a ANSI (multi byte, ansi code page)
+ *  string based on the wide char string passed in.
+ *
+ * NOTE:  inWideStringChars is number of wide characters in outWideString,
+ *          NOT the number of bytes....
+ */
+LPSTR _PR_MD_W2A(LPCWSTR inWideString, LPSTR outString, int inStringChars);
+
 #if defined(WINCE)
 /*
  * WinCE Only
  *
  * Some of the functions we intend to proxy to get around multi-byte API
  *  assumptions are imported from DLLs.  I would rather not fake out
  *  the linkage by prepending _imp_ ## functioname to make things happen.
  * We need to provide our own linkage symbol for all this to work out.
--- a/pr/include/md/_wince.h
+++ b/pr/include/md/_wince.h
@@ -548,16 +548,18 @@ struct tm {
     int tm_mon;
     int tm_year;
     int tm_wday;
     int tm_yday;
     int tm_isdst;
 };
 extern struct tm* Wingmtime(const time_t* inTimeT);
 extern struct tm* Winlocaltime(const time_t* inTimeT);
+extern struct tm* Wingmtime_r(const time_t* inTimeT, struct tm* outRetval);
+extern struct tm* Winlocaltime_r(const time_t* inTimeT, struct tm* outRetval);
 extern time_t Winmktime(struct tm* inTM);
 extern size_t Winstrftime(char *strDest, size_t maxsize, const char *format, const struct tm *timeptr);
 
 /*
  * struct protoent is actually defined, but the functions that use it are not.
  *
  * And related windows specific functions to mimic these absent sockets funcs.
  */
--- a/pr/src/md/windows/w32time.c
+++ b/pr/src/md/windows/w32time.c
@@ -52,108 +52,116 @@ static const int sDaysOfYear[12] = {
 };
 static struct tm tmStorage;
 
 /*
  *  Winlocaltime
  *
  *  As LIBC localtime
  */
-struct tm* Winlocaltime(const time_t* inTimeT)
+struct tm* Winlocaltime_r(const time_t* inTimeT, struct tm* outRetval)
 {
     struct tm* retval = NULL;
 
-    if(NULL != inTimeT)
+    if(NULL != inTimeT && NULL != outRetval)
     {
         SYSTEMTIME winLocalTime;
         
         _MD_time_t_2_LOCALSYSTEMTIME(winLocalTime, *inTimeT);
         
-        tmStorage.tm_sec = (int)winLocalTime.wSecond;
-        tmStorage.tm_min = (int)winLocalTime.wMinute;
-        tmStorage.tm_hour = (int)winLocalTime.wHour;
-        tmStorage.tm_mday = (int)winLocalTime.wDay;
-        tmStorage.tm_mon = (int)(winLocalTime.wMonth - 1);
-        tmStorage.tm_year = (int)(winLocalTime.wYear - 1900);
-        tmStorage.tm_wday = (int)winLocalTime.wDayOfWeek;
-        tmStorage.tm_isdst = -1;
+        outRetval->tm_sec = (int)winLocalTime.wSecond;
+        outRetval->tm_min = (int)winLocalTime.wMinute;
+        outRetval->tm_hour = (int)winLocalTime.wHour;
+        outRetval->tm_mday = (int)winLocalTime.wDay;
+        outRetval->tm_mon = (int)(winLocalTime.wMonth - 1);
+        outRetval->tm_year = (int)(winLocalTime.wYear - 1900);
+        outRetval->tm_wday = (int)winLocalTime.wDayOfWeek;
+        outRetval->tm_isdst = -1;
 
-        tmStorage.tm_yday = (int)winLocalTime.wDay + sDaysOfYear[tmStorage.tm_mon];
+        outRetval->tm_yday = (int)winLocalTime.wDay + sDaysOfYear[outRetval->tm_mon];
         if(0 == (winLocalTime.wYear & 3))
         {
             if(2 < winLocalTime.wMonth)
             {
                 if(0 == winLocalTime.wYear % 100)
                 {
                     if(0 == winLocalTime.wYear % 400)
                     {
-                        tmStorage.tm_yday++;
+                        outRetval->tm_yday++;
                     }
                 }
                 else
                 {
-                    tmStorage.tm_yday++;
+                    outRetval->tm_yday++;
                 }
             }
         }
 
         retval = &tmStorage;
     }
 
     return retval;
 }
+struct tm* Winlocaltime(const time_t* inTimeT)
+{
+    return Winlocaltime_r(inTimeT, &tmStorage);
+}
 
 /*
  *  Wingmtime
  *
  *  As LIBC gmtime
  */
-struct tm* Wingmtime(const time_t* inTimeT)
+struct tm* Wingmtime_r(const time_t* inTimeT, struct tm* outRetval)
 {
     struct tm* retval = NULL;
 
     if(NULL != inTimeT)
     {
         SYSTEMTIME winGMTime;
         
         _MD_time_t_2_SYSTEMTIME(winGMTime, *inTimeT);
         
-        tmStorage.tm_sec = (int)winGMTime.wSecond;
-        tmStorage.tm_min = (int)winGMTime.wMinute;
-        tmStorage.tm_hour = (int)winGMTime.wHour;
-        tmStorage.tm_mday = (int)winGMTime.wDay;
-        tmStorage.tm_mon = (int)(winGMTime.wMonth - 1);
-        tmStorage.tm_year = (int)(winGMTime.wYear - 1900);
-        tmStorage.tm_wday = (int)winGMTime.wDayOfWeek;
-        tmStorage.tm_isdst = -1;
+        outRetval->tm_sec = (int)winGMTime.wSecond;
+        outRetval->tm_min = (int)winGMTime.wMinute;
+        outRetval->tm_hour = (int)winGMTime.wHour;
+        outRetval->tm_mday = (int)winGMTime.wDay;
+        outRetval->tm_mon = (int)(winGMTime.wMonth - 1);
+        outRetval->tm_year = (int)(winGMTime.wYear - 1900);
+        outRetval->tm_wday = (int)winGMTime.wDayOfWeek;
+        outRetval->tm_isdst = -1;
 
-        tmStorage.tm_yday = (int)winGMTime.wDay + sDaysOfYear[tmStorage.tm_mon];
+        outRetval->tm_yday = (int)winGMTime.wDay + sDaysOfYear[outRetval->tm_mon];
         if(0 == (winGMTime.wYear & 3))
         {
             if(2 < winGMTime.wMonth)
             {
                 if(0 == winGMTime.wYear % 100)
                 {
                     if(0 == winGMTime.wYear % 400)
                     {
-                        tmStorage.tm_yday++;
+                        outRetval->tm_yday++;
                     }
                 }
                 else
                 {
-                    tmStorage.tm_yday++;
+                    outRetval->tm_yday++;
                 }
             }
         }
 
         retval = &tmStorage;
     }
 
     return retval;
 }
+struct tm* Wingmtime(const time_t* inTimeT)
+{
+    return Wingmtime_r(inTimeT, &tmStorage);
+}
 
 /*
  *  Winmktime
  *
  *  As LIBCs mktime
  *  We likely have a deficiency with the handling of tm_isdst...
  */
 time_t Winmktime(struct tm* inTM)
@@ -180,36 +188,388 @@ time_t Winmktime(struct tm* inTM)
         /*
          * First get our time_t.
          */
         _MD_SYSTEMTIME_2_time_t(retval, winTime);
 
         /*
          * Now overwrite the struct passed in with what we believe it should be.
          */
-        gmTime = Wingmtime(&retval);
-        if(gmTime != inTM)
-        {
-            memcpy(inTM, gmTime, sizeof(struct tm));
-        }
+        gmTime = Wingmtime_r(&retval, inTM);
     }
 
     return retval;
 }
 
+static void helper_Winstrftime(LPCWSTR inWStr, char** outAStr, int* outAStrMax, PRBool* outHadError, PRBool* outEnoughSpace, char inTestEnd)
+{
+    char *w2aRes = NULL;
+
+    w2aRes = _PR_MD_W2A(inWStr, *outAStr, *outAStrMax);
+    if(NULL != w2aRes)
+    {
+        size_t written = strlen(*outAStr);
+
+        (*outAStr) += written;
+        (*outAStrMax) -= written;
+
+        if(0 == (*outAStrMax) && '\0' != inTestEnd)
+        {
+            /* next one will fail actually, not this one */
+            *outEnoughSpace = PR_FALSE;
+        }
+    }
+    else
+    {
+        *outHadError = PR_TRUE;
+    }
+}
+
 /*
  *  Winstrftime
  *
  *  As LIBCs strftime
+ *  Use GetTimeFormat and GetDateFormat to implement.
  */
 size_t Winstrftime(char *strDest, size_t maxsize, const char *format, const struct tm *timeptr)
 {
     size_t retval = 0;
 
-    /*
-    ** FIXME TODO
-    **
-    ** Use GetTimeFormat and GetDateFormat to implement this for real.
-    */
-    PR_ASSERT(0);
+    if(NULL != strDest && 0 != maxsize && NULL != format && NULL != timeptr)
+    {
+        const char* traverse = format;
+        char* outDst = strDest;
+        size_t outMax = maxsize - 1;
+        PRBool hadEnoughSpace = PR_TRUE;
+        struct tm convertTM;
+        time_t convertT;
+        SYSTEMTIME sysTime;
+        PRBool errorOut = PR_FALSE;
+
+        /*
+         * Convert the struct tm to SYSTEMTIME.
+         * The SYSTEMTIME will be used in the API calls.
+         */
+        memcpy(&convertTM, timeptr, sizeof(convertTM));
+        convertT = Winmktime(&convertTM);
+        _MD_time_t_2_SYSTEMTIME(sysTime, convertT);
+
+        /*
+         * Format may be empty string.
+         */
+        *outDst = '\0';
+
+        /*
+         * Loop over the format and do the right thing.
+         */
+        while('\0' != *traverse && PR_TRUE == hadEnoughSpace && PR_FALSE == errorOut)
+        {
+            switch(*traverse)
+            {
+            case '%':
+                {
+                    PRIntn offset = 0;
+                    PRBool poundOutput = PR_FALSE;
+                    WCHAR buf[128];
+
+                    traverse++;
+                    offset++;
+
+                    /*
+                     * Skip the '#' formatting option.
+                     */
+                    if('#' == *traverse)
+                    {
+                        traverse++;
+                        offset++;
+                        poundOutput = PR_TRUE;
+                    }
+
+                    switch(*traverse)
+                    {
+                    case 'a':
+                        {
+                            int getRes = 0;
+
+                            /*
+                             * Abbreviated weekday name.
+                             */
+                            traverse++;
+                            getRes = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &sysTime, _T("ddd"), buf, sizeof(buf) / sizeof(WCHAR));
+                            if(0 != getRes)
+                            {
+                                helper_Winstrftime(buf, &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                            }
+                            else
+                            {
+                                errorOut = PR_TRUE;
+                            }
+                        }
+                        break;
+                    case 'A':
+                        {
+                            int getRes = 0;
+
+                            /*
+                             * Full weekday name.
+                             */
+                            traverse++;
+                            getRes = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &sysTime, _T("dddd"), buf, sizeof(buf) / sizeof(WCHAR));
+                            if(0 != getRes)
+                            {
+                                helper_Winstrftime(buf, &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                            }
+                            else
+                            {
+                                errorOut = PR_TRUE;
+                            }
+                        }
+                        break;
+                    case 'b':
+                        {
+                            int getRes = 0;
+
+                            /*
+                             * Abbreviated month name.
+                             */
+                            traverse++;
+                            getRes = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &sysTime, _T("MMM"), buf, sizeof(buf) / sizeof(WCHAR));
+                            if(0 != getRes)
+                            {
+                                helper_Winstrftime(buf, &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                            }
+                            else
+                            {
+                                errorOut = PR_TRUE;
+                            }
+                        }
+                        break;
+                    case 'B':
+                        {
+                            int getRes = 0;
+
+                            /*
+                             * Full month name.
+                             */
+                            traverse++;
+                            getRes = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &sysTime, _T("MMMM"), buf, sizeof(buf) / sizeof(WCHAR));
+                            if(0 != getRes)
+                            {
+                                helper_Winstrftime(buf, &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                            }
+                            else
+                            {
+                                errorOut = PR_TRUE;
+                            }
+                        }
+                        break;
+                    case 'c':
+                        {
+                            int getRes = 0;
+
+                            /*
+                             * Date and time representation for locale.
+                             */
+                            traverse++;
+
+                            /*
+                             * First the date.
+                             */
+                            getRes = GetDateFormatW(LOCALE_USER_DEFAULT, (PR_TRUE == poundOutput) ? DATE_LONGDATE : DATE_SHORTDATE, &sysTime, NULL, buf, sizeof(buf) / sizeof(WCHAR));
+                            if(0 != getRes)
+                            {
+                                helper_Winstrftime(buf, &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                            }
+                            else
+                            {
+                                errorOut = PR_TRUE;
+                            }
+
+                            /*
+                             * Uhm, a guess just a space between date and time.
+                             */
+                            helper_Winstrftime(_T(" "), &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+
+
+                            /*
+                             * Last the time.
+                             */
+                            getRes = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &sysTime, NULL, buf, sizeof(buf) / sizeof(WCHAR));
+                            if(0 != getRes)
+                            {
+                                helper_Winstrftime(buf, &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                            }
+                            else
+                            {
+                                errorOut = PR_TRUE;
+                            }
+                        }
+                        break;
+                    case 'd':
+                        {
+                            int getRes = 0;
+
+                            /*
+                             * Day of month as decimal.
+                             */
+                            traverse++;
+                            getRes = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &sysTime, (PR_TRUE == poundOutput) ? _T("d") : _T("dd"), buf, sizeof(buf) / sizeof(WCHAR));
+                            if(0 != getRes)
+                            {
+                                helper_Winstrftime(buf, &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                            }
+                            else
+                            {
+                                errorOut = PR_TRUE;
+                            }
+                        }
+                        break;
+                    case 'H':
+                        {
+                            int getRes = 0;
+
+                            /*
+                             * Hour in 24 hour format.
+                             */
+                            traverse++;
+                            getRes = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &sysTime, (PR_TRUE == poundOutput) ? _T("H") : _T("HH"), buf, sizeof(buf) / sizeof(WCHAR));
+                            if(0 != getRes)
+                            {
+                                helper_Winstrftime(buf, &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                            }
+                            else
+                            {
+                                errorOut = PR_TRUE;
+                            }
+                        }
+                        break;
+                    case 'I':
+                        {
+                            int getRes = 0;
+
+                            /*
+                             * Hour in 12 hour format.
+                             */
+                            traverse++;
+                            getRes = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &sysTime, (PR_TRUE == poundOutput) ? _T("h") : _T("hh"), buf, sizeof(buf) / sizeof(WCHAR));
+                            if(0 != getRes)
+                            {
+                                helper_Winstrftime(buf, &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                            }
+                            else
+                            {
+                                errorOut = PR_TRUE;
+                            }
+                        }
+                        break;
+                    case 'j':
+                        PR_ASSERT(0);
+                        break;
+                    case 'm':
+                        PR_ASSERT(0);
+                        break;
+                    case 'M':
+                        PR_ASSERT(0);
+                        break;
+                    case 'p':
+                        PR_ASSERT(0);
+                        break;
+                    case 'S':
+                        PR_ASSERT(0);
+                        break;
+                    case 'U':
+                        PR_ASSERT(0);
+                        break;
+                    case 'w':
+                        PR_ASSERT(0);
+                        break;
+                    case 'W':
+                        PR_ASSERT(0);
+                        break;
+                    case 'x':
+                        PR_ASSERT(0);
+                        break;
+                    case 'X':
+                        PR_ASSERT(0);
+                        break;
+                    case 'y':
+                        PR_ASSERT(0);
+                        break;
+                    case 'Y':
+                        PR_ASSERT(0);
+                        break;
+                    case 'z':
+                        PR_ASSERT(0);
+                        break;
+                    case 'Z':
+                        PR_ASSERT(0);
+                        break;
+                    case '%':
+                        {
+                            /*
+                             * A signle percent.
+                             */
+                            traverse++;
+                            helper_Winstrftime(_T("%"), &outDst, &outMax, &errorOut, &hadEnoughSpace, *traverse);
+                        }
+                        break;
+                    default:
+                        {
+                            /*
+                             * Unrecognized formatting option.
+                             * Back up and just output it.
+                             */
+                            traverse -= offset;
+
+                            outDst[0] = *traverse;
+                            outDst[1] = '\0';
+
+                            outMax--;
+                            outDst++;
+                            traverse++;
+
+                            /*
+                             * Check to see if we used it all up.
+                             */
+                            if(0 == outMax && '\0' != *traverse)
+                            {
+                                hadEnoughSpace = PR_FALSE;
+                            }
+                        }
+                        break;
+                    }
+                }
+                break;
+            default:
+                {
+                    /*
+                     * Add custom formatting to output.
+                     */
+                    outDst[0] = *traverse;
+                    outDst[1] = '\0';
+
+                    outMax--;
+                    outDst++;
+                    traverse++;
+
+                    /*
+                     * Check to see if we used it all up.
+                     */
+                    if(0 == outMax && '\0' != *traverse)
+                    {
+                        hadEnoughSpace = PR_FALSE;
+                    }
+                }
+                break;
+            }
+        }
+
+        if(PR_FALSE == errorOut && PR_TRUE == hadEnoughSpace)
+        {
+            /*
+             * Number of chars written is return value.
+             */
+            retval = maxsize - outMax;
+        }
+    }
 
     return retval;
 }
--- a/pr/src/md/windows/w32unicode.c
+++ b/pr/src/md/windows/w32unicode.c
@@ -117,16 +117,52 @@ LPWSTR _PR_MD_A2W(LPCSTR inString, LPWST
         {
             retval = NULL;
         }
     }
 
     return retval;
 }
 
+/*
+ * _PR_MD_W2A
+ *
+ * Non-mallocing fucntion to return a ANSI (multi byte, ansi code page)
+ *  string based on the wide char string passed in.
+ *
+ * NOTE:  inWideStringChars is number of wide characters in outWideString,
+ *          NOT the number of bytes....
+ */
+LPSTR _PR_MD_W2A(LPCWSTR inWideString, LPSTR outString, int inStringChars)
+{
+    LPSTR retval = outString;
+
+    if(NULL != outString)
+    {
+        int convertRes = 0;
+
+        convertRes = WideCharToMultiByte(
+            CP_ACP,
+            WC_COMPOSITECHECK,
+            inWideString,
+            -1,
+            outString,
+            inStringChars,
+            NULL,
+            NULL
+            );
+        if(0 == convertRes)
+        {
+            retval = NULL;
+        }
+    }
+
+    return retval;
+}
+
 #if defined(WINCE)
 
 /*
 ** WINCE Only
 **
 ** This entire section of code dedicated to doing conversions between
 **  ANSI code page APIs and UNICODE APIs (funcA to funcW).
 ** This is similar to what NT does to support the funcAs.
--- a/pr/src/md/windows/w95io.c
+++ b/pr/src/md/windows/w95io.c
@@ -464,18 +464,17 @@ PRInt32
 /* --- DIR IO ------------------------------------------------------------ */
 #if !defined(WINCE)
 #define GetFileFromDIR(d)       (d)->d_entry.cFileName
 #else
 char* GetFileFromDIR(_MDDir* d)
 {
     char* retval = NULL;
 
-    WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, d->d_entry.cFileName, -1, d->cFileNameA, sizeof(d->cFileNameA), NULL, NULL);
-    retval = d->cFileNameA;
+    retval = _PR_MD_W2A(d->d_entry.cFileName, d->cFileNameA, sizeof(d->cFileNameA));
 
     return retval;
 }
 #endif
 #define FileIsHidden(d)	((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
 
 void FlipSlashes(char *cp, int len)
 {