summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin v. Löwis <martin@v.loewis.de>2009-05-30 06:13:40 (GMT)
committerMartin v. Löwis <martin@v.loewis.de>2009-05-30 06:13:40 (GMT)
commit1b01ccd76a5dfd00efe07af0e942afe0b59de63a (patch)
tree3b6ef6011febf085aff6d91771ceeabdfbf85cae
parent3ad05763a6d69a93e58dfef6cc9d84f14edbb29b (diff)
downloadcpython-1b01ccd76a5dfd00efe07af0e942afe0b59de63a.zip
cpython-1b01ccd76a5dfd00efe07af0e942afe0b59de63a.tar.gz
cpython-1b01ccd76a5dfd00efe07af0e942afe0b59de63a.tar.bz2
Issue #5562: Use wcsftime for time.strftime where available.
-rw-r--r--Lib/test/test_time.py21
-rw-r--r--Misc/NEWS2
-rw-r--r--Modules/timemodule.c51
-rw-r--r--PC/pyconfig.h3
4 files changed, 65 insertions, 12 deletions
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
index c2dfaca..4e21a64 100644
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -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()
diff --git a/Misc/NEWS b/Misc/NEWS
index 1e12773..e7a425a 100644
--- 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.
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index 2727297..d524ac5 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -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\
diff --git a/PC/pyconfig.h b/PC/pyconfig.h
index e0c9f48..d76846f 100644
--- a/PC/pyconfig.h
+++ b/PC/pyconfig.h
@@ -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