mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #5562: Use wcsftime for time.strftime where available.
This commit is contained in:
parent
3ad05763a6
commit
1b01ccd76a
4 changed files with 65 additions and 12 deletions
|
@ -1,7 +1,7 @@
|
||||||
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):
|
||||||
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
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
#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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
#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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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 */
|
||||||
/* 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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue