]> granicus.if.org Git - python/commitdiff
Issue #5562: Use wcsftime for time.strftime where available.
authorMartin v. Löwis <martin@v.loewis.de>
Sat, 30 May 2009 06:13:40 +0000 (06:13 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Sat, 30 May 2009 06:13:40 +0000 (06:13 +0000)
Lib/test/test_time.py
Misc/NEWS
Modules/timemodule.c
PC/pyconfig.h

index c2dfaca968ced6b1625386f207ac9cb2ecca2c32..4e21a64be0a9c087252640888eae3b6098882aa4 100644 (file)
@@ -1,7 +1,7 @@
 from test import support
 import time
 import unittest
-
+import locale
 
 class TimeTestCase(unittest.TestCase):
 
@@ -223,9 +223,24 @@ class TimeTestCase(unittest.TestCase):
         t1 = time.mktime(lt1)
         self.assert_(0 <= (t1-t0) < 0.2)
 
-def test_main():
-    support.run_unittest(TimeTestCase)
+class TestLocale(unittest.TestCase):
+    def setUp(self):
+        self.oldloc = locale.setlocale(locale.LC_ALL)
+
+    def tearDown(self):
+        locale.setlocale(locale.LC_ALL, self.oldloc)
 
+    def test_bug_5562(self):
+        try:
+            tmp = locale.setlocale(locale.LC_ALL, "fr_FR")
+        except locale.Error:
+            # skip this test
+            return
+        # This should not cause an exception
+        time.strftime("%B", (2009,2,1,0,0,0,0,0,0))
+
+def test_main():
+    support.run_unittest(TimeTestCase, TestLocale)
 
 if __name__ == "__main__":
     test_main()
index 1e1277327a2fe7a138c27f2f356e787d6693fec8..e7a425a0389149bcccc6f79e2328f1f01801e63e 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -111,6 +111,8 @@ Installation
 Extension Modules
 -----------------
 
+- Issue #5562: Use wcsftime for time.strftime where available.
+
 - Issue #4873: Fix resource leaks in error cases of pwd and grp.
 
 - Issue #6093: Fix off-by-one error in locale.strxfrm.
index 27272977922cc1225d968c2886a9e8aa658bc565..d524ac549aa0b4fd5efaaba5c337e2a8a661b323 100644 (file)
@@ -417,15 +417,25 @@ gettmarg(PyObject *args, struct tm *p)
 }
 
 #ifdef HAVE_STRFTIME
+#ifdef HAVE_WCSFTIME
+#define time_char wchar_t
+#define format_time wcsftime
+#define time_strlen wcslen
+#else
+#define time_char char
+#define format_time strftime
+#define time_strlen strlen
+#endif
+
 static PyObject *
 time_strftime(PyObject *self, PyObject *args)
 {
        PyObject *tup = NULL;
        struct tm buf;
-       const char *fmt;
-       PyObject *format;
+       const time_char *fmt;
+       PyObject *format, *tmpfmt;
        size_t fmtlen, buflen;
-       char *outbuf = 0;
+       time_char *outbuf = 0;
        size_t i;
 
        memset((void *) &buf, '\0', sizeof(buf));
@@ -508,22 +518,38 @@ time_strftime(PyObject *self, PyObject *args)
             return NULL;
         }
 
+#ifdef HAVE_WCSFTIME
+       tmpfmt = PyBytes_FromStringAndSize(NULL,
+                                          sizeof(wchar_t) * (PyUnicode_GetSize(format)+1));
+       if (!tmpfmt)
+               return NULL;
+       /* This assumes that PyUnicode_AsWideChar doesn't do any UTF-16
+          expansion. */
+       if (PyUnicode_AsWideChar((PyUnicodeObject*)format,
+                                (wchar_t*)PyBytes_AS_STRING(tmpfmt),
+                                PyUnicode_GetSize(format)+1) == (size_t)-1)
+               /* This shouldn't fail. */
+               Py_FatalError("PyUnicode_AsWideChar failed");
+       format = tmpfmt;
+       fmt = (wchar_t*)PyBytes_AS_STRING(format);
+#else
        /* Convert the unicode string to an ascii one */
        format = PyUnicode_AsEncodedString(format, TZNAME_ENCODING, NULL);
        if (format == NULL)
                return NULL;
        fmt = PyBytes_AS_STRING(format);
+#endif
 
 #ifdef MS_WINDOWS
        /* check that the format string contains only valid directives */
-       for(outbuf = strchr(fmt, '%');
+       for(outbuf = wcschr(fmt, L'%');
                outbuf != NULL;
-               outbuf = strchr(outbuf+2, '%'))
+               outbuf = wcschr(outbuf+2, L'%'))
        {
                if (outbuf[1]=='#')
                        ++outbuf; /* not documented by python, */
                if (outbuf[1]=='\0' ||
-                       !strchr("aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1]))
+                       !wcschr(L"aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1]))
                {
                        PyErr_SetString(PyExc_ValueError, "Invalid format string");
                        return 0;
@@ -531,18 +557,18 @@ time_strftime(PyObject *self, PyObject *args)
        }
 #endif
 
-       fmtlen = strlen(fmt);
+       fmtlen = time_strlen(fmt);
 
        /* I hate these functions that presume you know how big the output
         * will be ahead of time...
         */
        for (i = 1024; ; i += i) {
-               outbuf = (char *)PyMem_Malloc(i);
+               outbuf = (time_char *)PyMem_Malloc(i*sizeof(time_char));
                if (outbuf == NULL) {
                        Py_DECREF(format);
                        return PyErr_NoMemory();
                }
-               buflen = strftime(outbuf, i, fmt, &buf);
+               buflen = format_time(outbuf, i, fmt, &buf);
                if (buflen > 0 || i >= 256 * fmtlen) {
                        /* If the buffer is 256 times as long as the format,
                           it's probably not failing for lack of room!
@@ -550,8 +576,12 @@ time_strftime(PyObject *self, PyObject *args)
                           e.g. an empty format, or %Z when the timezone
                           is unknown. */
                        PyObject *ret;
+#ifdef HAVE_WCSFTIME
+                       ret = PyUnicode_FromWideChar(outbuf, buflen);
+#else
                        ret = PyUnicode_Decode(outbuf, buflen,
                                               TZNAME_ENCODING, NULL);
+#endif
                        PyMem_Free(outbuf);
                        Py_DECREF(format);
                        return ret;
@@ -568,6 +598,9 @@ time_strftime(PyObject *self, PyObject *args)
        }
 }
 
+#undef time_char
+#undef format_time
+
 PyDoc_STRVAR(strftime_doc,
 "strftime(format[, tuple]) -> string\n\
 \n\
index e0c9f48f9670a91461507583802c5895258f2722..d76846fe403150284864b991c5aea78e992618ed 100644 (file)
@@ -637,6 +637,9 @@ Py_NO_ENABLE_SHARED to find out.  Also support MS_NO_COREDLL for b/w compat */
 /* Define if you have waitpid.  */
 /* #undef HAVE_WAITPID */
 
+/* Define to 1 if you have the `wcsftime' function. */
+#define HAVE_WCSFTIME 1
+
 /* Define to 1 if you have the `wcscoll' function. */
 #ifndef MS_WINCE
 #define HAVE_WCSCOLL 1