Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1b01ccd

Browse files
committed
Issue #5562: Use wcsftime for time.strftime where available.
1 parent 3ad0576 commit 1b01ccd

4 files changed

Lines changed: 65 additions & 12 deletions

File tree

Lib/test/test_time.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from test import support
22
import time
33
import unittest
4-
4+
import locale
55

66
class TimeTestCase(unittest.TestCase):
77

@@ -223,9 +223,24 @@ def test_localtime_without_arg(self):
223223
t1 = time.mktime(lt1)
224224
self.assert_(0 <= (t1-t0) < 0.2)
225225

226-
def test_main():
227-
support.run_unittest(TimeTestCase)
226+
class TestLocale(unittest.TestCase):
227+
def setUp(self):
228+
self.oldloc = locale.setlocale(locale.LC_ALL)
229+
230+
def tearDown(self):
231+
locale.setlocale(locale.LC_ALL, self.oldloc)
228232

233+
def test_bug_5562(self):
234+
try:
235+
tmp = locale.setlocale(locale.LC_ALL, "fr_FR")
236+
except locale.Error:
237+
# skip this test
238+
return
239+
# This should not cause an exception
240+
time.strftime("%B", (2009,2,1,0,0,0,0,0,0))
241+
242+
def test_main():
243+
support.run_unittest(TimeTestCase, TestLocale)
229244

230245
if __name__ == "__main__":
231246
test_main()

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ Installation
111111
Extension Modules
112112
-----------------
113113

114+
- Issue #5562: Use wcsftime for time.strftime where available.
115+
114116
- Issue #4873: Fix resource leaks in error cases of pwd and grp.
115117

116118
- Issue #6093: Fix off-by-one error in locale.strxfrm.

Modules/timemodule.c

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -417,15 +417,25 @@ gettmarg(PyObject *args, struct tm *p)
417417
}
418418

419419
#ifdef HAVE_STRFTIME
420+
#ifdef HAVE_WCSFTIME
421+
#define time_char wchar_t
422+
#define format_time wcsftime
423+
#define time_strlen wcslen
424+
#else
425+
#define time_char char
426+
#define format_time strftime
427+
#define time_strlen strlen
428+
#endif
429+
420430
static PyObject *
421431
time_strftime(PyObject *self, PyObject *args)
422432
{
423433
PyObject *tup = NULL;
424434
struct tm buf;
425-
const char *fmt;
426-
PyObject *format;
435+
const time_char *fmt;
436+
PyObject *format, *tmpfmt;
427437
size_t fmtlen, buflen;
428-
char *outbuf = 0;
438+
time_char *outbuf = 0;
429439
size_t i;
430440

431441
memset((void *) &buf, '\0', sizeof(buf));
@@ -508,50 +518,70 @@ time_strftime(PyObject *self, PyObject *args)
508518
return NULL;
509519
}
510520

521+
#ifdef HAVE_WCSFTIME
522+
tmpfmt = PyBytes_FromStringAndSize(NULL,
523+
sizeof(wchar_t) * (PyUnicode_GetSize(format)+1));
524+
if (!tmpfmt)
525+
return NULL;
526+
/* This assumes that PyUnicode_AsWideChar doesn't do any UTF-16
527+
expansion. */
528+
if (PyUnicode_AsWideChar((PyUnicodeObject*)format,
529+
(wchar_t*)PyBytes_AS_STRING(tmpfmt),
530+
PyUnicode_GetSize(format)+1) == (size_t)-1)
531+
/* This shouldn't fail. */
532+
Py_FatalError("PyUnicode_AsWideChar failed");
533+
format = tmpfmt;
534+
fmt = (wchar_t*)PyBytes_AS_STRING(format);
535+
#else
511536
/* Convert the unicode string to an ascii one */
512537
format = PyUnicode_AsEncodedString(format, TZNAME_ENCODING, NULL);
513538
if (format == NULL)
514539
return NULL;
515540
fmt = PyBytes_AS_STRING(format);
541+
#endif
516542

517543
#ifdef MS_WINDOWS
518544
/* check that the format string contains only valid directives */
519-
for(outbuf = strchr(fmt, '%');
545+
for(outbuf = wcschr(fmt, L'%');
520546
outbuf != NULL;
521-
outbuf = strchr(outbuf+2, '%'))
547+
outbuf = wcschr(outbuf+2, L'%'))
522548
{
523549
if (outbuf[1]=='#')
524550
++outbuf; /* not documented by python, */
525551
if (outbuf[1]=='\0' ||
526-
!strchr("aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1]))
552+
!wcschr(L"aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1]))
527553
{
528554
PyErr_SetString(PyExc_ValueError, "Invalid format string");
529555
return 0;
530556
}
531557
}
532558
#endif
533559

534-
fmtlen = strlen(fmt);
560+
fmtlen = time_strlen(fmt);
535561

536562
/* I hate these functions that presume you know how big the output
537563
* will be ahead of time...
538564
*/
539565
for (i = 1024; ; i += i) {
540-
outbuf = (char *)PyMem_Malloc(i);
566+
outbuf = (time_char *)PyMem_Malloc(i*sizeof(time_char));
541567
if (outbuf == NULL) {
542568
Py_DECREF(format);
543569
return PyErr_NoMemory();
544570
}
545-
buflen = strftime(outbuf, i, fmt, &buf);
571+
buflen = format_time(outbuf, i, fmt, &buf);
546572
if (buflen > 0 || i >= 256 * fmtlen) {
547573
/* If the buffer is 256 times as long as the format,
548574
it's probably not failing for lack of room!
549575
More likely, the format yields an empty result,
550576
e.g. an empty format, or %Z when the timezone
551577
is unknown. */
552578
PyObject *ret;
579+
#ifdef HAVE_WCSFTIME
580+
ret = PyUnicode_FromWideChar(outbuf, buflen);
581+
#else
553582
ret = PyUnicode_Decode(outbuf, buflen,
554583
TZNAME_ENCODING, NULL);
584+
#endif
555585
PyMem_Free(outbuf);
556586
Py_DECREF(format);
557587
return ret;
@@ -568,6 +598,9 @@ time_strftime(PyObject *self, PyObject *args)
568598
}
569599
}
570600

601+
#undef time_char
602+
#undef format_time
603+
571604
PyDoc_STRVAR(strftime_doc,
572605
"strftime(format[, tuple]) -> string\n\
573606
\n\

PC/pyconfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,9 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */
637637
/* Define if you have waitpid. */
638638
/* #undef HAVE_WAITPID */
639639

640+
/* Define to 1 if you have the `wcsftime' function. */
641+
#define HAVE_WCSFTIME 1
642+
640643
/* Define to 1 if you have the `wcscoll' function. */
641644
#ifndef MS_WINCE
642645
#define HAVE_WCSCOLL 1

0 commit comments

Comments
 (0)