diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index 253a4dc..b643d9b 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -352,15 +352,12 @@ PyDoc_STRVAR(strxfrm__doc__, "string -> string. Returns a string that behaves for cmp locale-aware."); static PyObject* -PyLocale_strxfrm(PyObject* self, PyObject* args) +strxfrm_string(PyObject* self, char *s) { - char *s, *buf; + char *buf; size_t n1, n2; PyObject *result; - if (!PyArg_ParseTuple(args, "s:strxfrm", &s)) - return NULL; - /* assume no change in size, first */ n1 = strlen(s) + 1; buf = PyMem_Malloc(n1); @@ -376,7 +373,66 @@ PyLocale_strxfrm(PyObject* self, PyObject* args) } result = PyString_FromString(buf); PyMem_Free(buf); + + return result; +} + +static PyObject* +PyLocale_strxfrm(PyObject* self, PyObject* args) +{ +#if !defined(HAVE_WCSXFRM) || !defined(Py_USING_UNICODE) + char *s; + if (!PyArg_ParseTuple(args, "s:strxfrm", &s)) + return NULL; + return strxfrm_string(self, s); +#else + PyObject *os, *result = NULL; + wchar_t *ws = NULL; + int len; + wchar_t *buf; + size_t n1, n2; + + if (!PyArg_UnpackTuple(args, "strxfrm", 1, 1, &os)) + return NULL; + if (PyString_Check(os)) + return strxfrm_string(self, PyString_AS_STRING(os)); + if (!PyUnicode_Check(os)) + PyErr_SetString(PyExc_ValueError, "strxfrm arguments must be a string"); + + len = PyUnicode_GET_SIZE(os) + 1; + ws = PyMem_MALLOC(len * sizeof(wchar_t)); + if (!ws) { + PyErr_NoMemory(); + goto done; + } + if (PyUnicode_AsWideChar((PyUnicodeObject*)os, ws, len) == -1) + goto done; + ws[len - 1] = 0; + + /* assume no change in size, first */ + n1 = len + 1; + buf = PyMem_Malloc(n1 * sizeof(wchar_t)); + if (!buf) { + PyErr_NoMemory(); + goto done; + } + n2 = wcsxfrm(buf, ws, n1) + 1; + if (n2 > n1) { + /* more space needed */ + buf = PyMem_Realloc(buf, n2 * sizeof(wchar_t)); + if (!buf) { + PyErr_NoMemory(); + goto done; + } + n2 = wcsxfrm(buf, ws, n2) + 1; + } + result = PyUnicode_FromWideChar(buf, n2 - 1); + PyMem_Free(buf); + + done: + if (ws) PyMem_FREE(ws); return result; +#endif } #if defined(MS_WINDOWS) diff --git a/configure b/configure index 29ce00c..abeecc6 100755 --- a/configure +++ b/configure @@ -9560,7 +9560,7 @@ for ac_func in alarm setitimer getitimer bind_textdomain_codeset chown \ setsid setpgid setpgrp setuid setvbuf snprintf \ sigaction siginterrupt sigrelse strftime \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ - truncate uname unsetenv utimes waitpid wait3 wait4 wcscoll _getpty + truncate uname unsetenv utimes waitpid wait3 wait4 wcscoll wcsxfrm _getpty do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index ea106b5..d9a62c2 100644 --- a/configure.in +++ b/configure.in @@ -2729,7 +2729,7 @@ AC_CHECK_FUNCS(alarm setitimer getitimer bind_textdomain_codeset chown \ setsid setpgid setpgrp setuid setvbuf snprintf \ sigaction siginterrupt sigrelse strftime \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ - truncate uname unsetenv utimes waitpid wait3 wait4 wcscoll _getpty) + truncate uname unsetenv utimes waitpid wait3 wait4 wcscoll wcsxfrm _getpty) # For some functions, having a definition is not sufficient, since # we want to take their address. diff --git a/pyconfig.h.in b/pyconfig.h.in index 65ad7ac..d5a1424 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -885,6 +885,9 @@ /* Define to 1 if you have the `wcscoll' function. */ #undef HAVE_WCSCOLL +/* Define to 1 if you have the `wcsxfrm' function. */ +#undef HAVE_WCSXFRM + /* Define if tzset() actually switches the local timezone in a meaningful way. */ #undef HAVE_WORKING_TZSET