Commit 1b01ccd7 authored by Martin v. Löwis's avatar Martin v. Löwis

Issue #5562: Use wcsftime for time.strftime where available.

parent 3ad05763
from test import support from test import support
import time import time
import unittest import unittest
import locale
class TimeTestCase(unittest.TestCase): class TimeTestCase(unittest.TestCase):
...@@ -223,9 +223,24 @@ class TimeTestCase(unittest.TestCase): ...@@ -223,9 +223,24 @@ class TimeTestCase(unittest.TestCase):
t1 = time.mktime(lt1) t1 = time.mktime(lt1)
self.assert_(0 <= (t1-t0) < 0.2) self.assert_(0 <= (t1-t0) < 0.2)
def test_main(): class TestLocale(unittest.TestCase):
support.run_unittest(TimeTestCase) 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__": if __name__ == "__main__":
test_main() test_main()
...@@ -111,6 +111,8 @@ Installation ...@@ -111,6 +111,8 @@ Installation
Extension Modules Extension Modules
----------------- -----------------
- Issue #5562: Use wcsftime for time.strftime where available.
- Issue #4873: Fix resource leaks in error cases of pwd and grp. - Issue #4873: Fix resource leaks in error cases of pwd and grp.
- Issue #6093: Fix off-by-one error in locale.strxfrm. - Issue #6093: Fix off-by-one error in locale.strxfrm.
......
...@@ -417,15 +417,25 @@ gettmarg(PyObject *args, struct tm *p) ...@@ -417,15 +417,25 @@ gettmarg(PyObject *args, struct tm *p)
} }
#ifdef HAVE_STRFTIME #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 * static PyObject *
time_strftime(PyObject *self, PyObject *args) time_strftime(PyObject *self, PyObject *args)
{ {
PyObject *tup = NULL; PyObject *tup = NULL;
struct tm buf; struct tm buf;
const char *fmt; const time_char *fmt;
PyObject *format; PyObject *format, *tmpfmt;
size_t fmtlen, buflen; size_t fmtlen, buflen;
char *outbuf = 0; time_char *outbuf = 0;
size_t i; size_t i;
memset((void *) &buf, '\0', sizeof(buf)); memset((void *) &buf, '\0', sizeof(buf));
...@@ -508,22 +518,38 @@ time_strftime(PyObject *self, PyObject *args) ...@@ -508,22 +518,38 @@ time_strftime(PyObject *self, PyObject *args)
return NULL; 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 */ /* Convert the unicode string to an ascii one */
format = PyUnicode_AsEncodedString(format, TZNAME_ENCODING, NULL); format = PyUnicode_AsEncodedString(format, TZNAME_ENCODING, NULL);
if (format == NULL) if (format == NULL)
return NULL; return NULL;
fmt = PyBytes_AS_STRING(format); fmt = PyBytes_AS_STRING(format);
#endif
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
/* check that the format string contains only valid directives */ /* check that the format string contains only valid directives */
for(outbuf = strchr(fmt, '%'); for(outbuf = wcschr(fmt, L'%');
outbuf != NULL; outbuf != NULL;
outbuf = strchr(outbuf+2, '%')) outbuf = wcschr(outbuf+2, L'%'))
{ {
if (outbuf[1]=='#') if (outbuf[1]=='#')
++outbuf; /* not documented by python, */ ++outbuf; /* not documented by python, */
if (outbuf[1]=='\0' || if (outbuf[1]=='\0' ||
!strchr("aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1])) !wcschr(L"aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1]))
{ {
PyErr_SetString(PyExc_ValueError, "Invalid format string"); PyErr_SetString(PyExc_ValueError, "Invalid format string");
return 0; return 0;
...@@ -531,18 +557,18 @@ time_strftime(PyObject *self, PyObject *args) ...@@ -531,18 +557,18 @@ time_strftime(PyObject *self, PyObject *args)
} }
#endif #endif
fmtlen = strlen(fmt); fmtlen = time_strlen(fmt);
/* I hate these functions that presume you know how big the output /* I hate these functions that presume you know how big the output
* will be ahead of time... * will be ahead of time...
*/ */
for (i = 1024; ; i += i) { for (i = 1024; ; i += i) {
outbuf = (char *)PyMem_Malloc(i); outbuf = (time_char *)PyMem_Malloc(i*sizeof(time_char));
if (outbuf == NULL) { if (outbuf == NULL) {
Py_DECREF(format); Py_DECREF(format);
return PyErr_NoMemory(); return PyErr_NoMemory();
} }
buflen = strftime(outbuf, i, fmt, &buf); buflen = format_time(outbuf, i, fmt, &buf);
if (buflen > 0 || i >= 256 * fmtlen) { if (buflen > 0 || i >= 256 * fmtlen) {
/* If the buffer is 256 times as long as the format, /* If the buffer is 256 times as long as the format,
it's probably not failing for lack of room! it's probably not failing for lack of room!
...@@ -550,8 +576,12 @@ time_strftime(PyObject *self, PyObject *args) ...@@ -550,8 +576,12 @@ time_strftime(PyObject *self, PyObject *args)
e.g. an empty format, or %Z when the timezone e.g. an empty format, or %Z when the timezone
is unknown. */ is unknown. */
PyObject *ret; PyObject *ret;
#ifdef HAVE_WCSFTIME
ret = PyUnicode_FromWideChar(outbuf, buflen);
#else
ret = PyUnicode_Decode(outbuf, buflen, ret = PyUnicode_Decode(outbuf, buflen,
TZNAME_ENCODING, NULL); TZNAME_ENCODING, NULL);
#endif
PyMem_Free(outbuf); PyMem_Free(outbuf);
Py_DECREF(format); Py_DECREF(format);
return ret; return ret;
...@@ -568,6 +598,9 @@ time_strftime(PyObject *self, PyObject *args) ...@@ -568,6 +598,9 @@ time_strftime(PyObject *self, PyObject *args)
} }
} }
#undef time_char
#undef format_time
PyDoc_STRVAR(strftime_doc, PyDoc_STRVAR(strftime_doc,
"strftime(format[, tuple]) -> string\n\ "strftime(format[, tuple]) -> string\n\
\n\ \n\
......
...@@ -637,6 +637,9 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ ...@@ -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. */ /* Define if you have waitpid. */
/* #undef 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. */ /* Define to 1 if you have the `wcscoll' function. */
#ifndef MS_WINCE #ifndef MS_WINCE
#define HAVE_WCSCOLL 1 #define HAVE_WCSCOLL 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment