summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/ext/extending.tex2
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_testcapimodule.c50
-rw-r--r--Python/getargs.c8
4 files changed, 61 insertions, 2 deletions
diff --git a/Doc/ext/extending.tex b/Doc/ext/extending.tex
index 0051a02..d77a714 100644
--- a/Doc/ext/extending.tex
+++ b/Doc/ext/extending.tex
@@ -669,6 +669,8 @@ address you pass.
\item[\samp{u\#} (Unicode object) {[Py_UNICODE *, int]}]
This variant on \samp{u} stores into two C variables, the first one
a pointer to a Unicode data buffer, the second one its length.
+Non-Unicode objects are handled by interpreting their read buffer
+pointer as pointer to a Py_UNICODE array.
\item[\samp{es} (string, Unicode object or character buffer compatible
object) {[const char *encoding, char **buffer]}]
diff --git a/Misc/NEWS b/Misc/NEWS
index 1912dc2..4429f8e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -28,6 +28,9 @@ Build
C API
+- The "u#" parser marker will now pass through Unicode object as-is
+ without going through the buffer API.
+
- The enumerators of cmp_op have been renamed to use the prefix PyCmp_.
- An old #define of ANY as void has been removed from pyport.h. This
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 0f5fa7c..824ae87 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -307,6 +307,53 @@ test_L_code(PyObject *self, PyObject *args)
#endif /* ifdef HAVE_LONG_LONG */
+#ifdef Py_USING_UNICODE
+
+/* Test the u and u# codes for PyArg_ParseTuple. May leak memory in case
+ of an error.
+*/
+static PyObject *
+test_u_code(PyObject *self, PyObject *args)
+{
+ PyObject *tuple, *obj;
+ Py_UNICODE *value;
+ int len;
+
+ if (!PyArg_ParseTuple(args, ":test_u_code"))
+ return NULL;
+
+ tuple = PyTuple_New(1);
+ if (tuple == NULL)
+ return NULL;
+
+ obj = PyUnicode_Decode("test", strlen("test"),
+ "ascii", NULL);
+ if (obj == NULL)
+ return NULL;
+
+ PyTuple_SET_ITEM(tuple, 0, obj);
+
+ value = 0;
+ if (PyArg_ParseTuple(tuple, "u:test_u_code", &value) < 0)
+ return NULL;
+ if (value != PyUnicode_AS_UNICODE(obj))
+ return raiseTestError("test_u_code",
+ "u code returned wrong value for u'test'");
+ value = 0;
+ if (PyArg_ParseTuple(tuple, "u#:test_u_code", &value, &len) < 0)
+ return NULL;
+ if (value != PyUnicode_AS_UNICODE(obj) ||
+ len != PyUnicode_GET_SIZE(obj))
+ return raiseTestError("test_u_code",
+ "u# code returned wrong values for u'test'");
+
+ Py_DECREF(tuple);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#endif
+
static PyObject *
raise_exception(PyObject *self, PyObject *args)
{
@@ -343,6 +390,9 @@ static PyMethodDef TestMethods[] = {
{"test_longlong_api", test_longlong_api, METH_VARARGS},
{"test_L_code", test_L_code, METH_VARARGS},
#endif
+#ifdef Py_USING_UNICODE
+ {"test_u_code", test_u_code, METH_VARARGS},
+#endif
{NULL, NULL} /* sentinel */
};
diff --git a/Python/getargs.c b/Python/getargs.c
index 9df2a2e..411c695 100644
--- a/Python/getargs.c
+++ b/Python/getargs.c
@@ -838,16 +838,20 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
if (*format == '#') { /* any buffer-like object */
void **p = (void **)va_arg(*p_va, char **);
int *q = va_arg(*p_va, int *);
+ if (PyUnicode_Check(arg)) {
+ *p = PyUnicode_AS_UNICODE(arg);
+ *q = PyUnicode_GET_SIZE(arg);
+ }
+ else {
char *buf;
int count = convertbuffer(arg, p, &buf);
-
if (count < 0)
return converterr(buf, arg, msgbuf, bufsize);
*q = count/(sizeof(Py_UNICODE));
+ }
format++;
} else {
Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **);
-
if (PyUnicode_Check(arg))
*p = PyUnicode_AS_UNICODE(arg);
else