mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	[3.14] Revert "gh-112068: C API: Add support of nullable arguments in PyArg_Parse (GH-121303)" (GH-136991) (#137006)
This commit is contained in:
		
							parent
							
								
									c328d140eb
								
							
						
					
					
						commit
						805daa2edb
					
				
					 12 changed files with 144 additions and 322 deletions
				
			
		|  | @ -113,18 +113,14 @@ There are three ways strings and buffers can be converted to C: | |||
| ``z`` (:class:`str` or ``None``) [const char \*] | ||||
|    Like ``s``, but the Python object may also be ``None``, in which case the C | ||||
|    pointer is set to ``NULL``. | ||||
|    It is the same as ``s?`` with the C pointer was initialized to ``NULL``. | ||||
| 
 | ||||
| ``z*`` (:class:`str`, :term:`bytes-like object` or ``None``) [Py_buffer] | ||||
|    Like ``s*``, but the Python object may also be ``None``, in which case the | ||||
|    ``buf`` member of the :c:type:`Py_buffer` structure is set to ``NULL``. | ||||
|    It is the same as ``s*?`` with the ``buf`` member of the :c:type:`Py_buffer` | ||||
|    structure was initialized to ``NULL``. | ||||
| 
 | ||||
| ``z#`` (:class:`str`, read-only :term:`bytes-like object` or ``None``) [const char \*, :c:type:`Py_ssize_t`] | ||||
|    Like ``s#``, but the Python object may also be ``None``, in which case the C | ||||
|    pointer is set to ``NULL``. | ||||
|    It is the same as ``s#?`` with the C pointer was initialized to ``NULL``. | ||||
| 
 | ||||
| ``y`` (read-only :term:`bytes-like object`) [const char \*] | ||||
|    This format converts a bytes-like object to a C pointer to a | ||||
|  | @ -387,17 +383,6 @@ Other objects | |||
|       Non-tuple sequences are deprecated if *items* contains format units | ||||
|       which store a borrowed buffer or a borrowed reference. | ||||
| 
 | ||||
| ``unit?`` (anything or ``None``) [*matching-variable(s)*] | ||||
|    ``?`` modifies the behavior of the preceding format unit. | ||||
|    The C variable(s) corresponding to that parameter should be initialized | ||||
|    to their default value --- when the argument is ``None``, | ||||
|    :c:func:`PyArg_ParseTuple` does not touch the contents of the corresponding | ||||
|    C variable(s). | ||||
|    If the argument is not ``None``, it is parsed according to the specified | ||||
|    format unit. | ||||
| 
 | ||||
|    .. versionadded:: 3.14 | ||||
| 
 | ||||
| A few other characters have a meaning in a format string.  These may not occur | ||||
| inside nested parentheses.  They are: | ||||
| 
 | ||||
|  |  | |||
|  | @ -2940,11 +2940,6 @@ New features | |||
|   file. | ||||
|   (Contributed by Victor Stinner in :gh:`127350`.) | ||||
| 
 | ||||
| * Add support of nullable arguments in :c:func:`PyArg_ParseTuple` and | ||||
|   similar functions. | ||||
|   Adding ``?`` after any format unit makes ``None`` be accepted as a value. | ||||
|   (Contributed by Serhiy Storchaka in :gh:`112068`.) | ||||
| 
 | ||||
| * The ``k`` and ``K`` formats in :c:func:`PyArg_ParseTuple` and | ||||
|   similar functions now use :meth:`~object.__index__` if available, | ||||
|   like all other integer formats. | ||||
|  |  | |||
|  | @ -1389,123 +1389,6 @@ def test_nested_sequence(self): | |||
|                     "argument 1 must be sequence of length 1, not 0"): | ||||
|                 parse(([],), {}, '(' + f + ')', ['a']) | ||||
| 
 | ||||
|     def test_specific_type_errors(self): | ||||
|         parse = _testcapi.parse_tuple_and_keywords | ||||
| 
 | ||||
|         def check(format, arg, expected, got='list'): | ||||
|             errmsg = f'must be {expected}, not {got}' | ||||
|             with self.assertRaisesRegex(TypeError, errmsg): | ||||
|                 parse((arg,), {}, format, ['a']) | ||||
| 
 | ||||
|         check('k', [], 'int') | ||||
|         check('k?', [], 'int or None') | ||||
|         check('K', [], 'int') | ||||
|         check('K?', [], 'int or None') | ||||
|         check('c', [], 'a byte string of length 1') | ||||
|         check('c?', [], 'a byte string of length 1 or None') | ||||
|         check('c', b'abc', 'a byte string of length 1', | ||||
|               'a bytes object of length 3') | ||||
|         check('c?', b'abc', 'a byte string of length 1 or None', | ||||
|               'a bytes object of length 3') | ||||
|         check('c', bytearray(b'abc'), 'a byte string of length 1', | ||||
|               'a bytearray object of length 3') | ||||
|         check('c?', bytearray(b'abc'), 'a byte string of length 1 or None', | ||||
|               'a bytearray object of length 3') | ||||
|         check('C', [], 'a unicode character') | ||||
|         check('C?', [], 'a unicode character or None') | ||||
|         check('C', 'abc', 'a unicode character', | ||||
|               'a string of length 3') | ||||
|         check('C?', 'abc', 'a unicode character or None', | ||||
|               'a string of length 3') | ||||
|         check('s', [], 'str') | ||||
|         check('s?', [], 'str or None') | ||||
|         check('z', [], 'str or None') | ||||
|         check('z?', [], 'str or None') | ||||
|         check('es', [], 'str') | ||||
|         check('es?', [], 'str or None') | ||||
|         check('es#', [], 'str') | ||||
|         check('es#?', [], 'str or None') | ||||
|         check('et', [], 'str, bytes or bytearray') | ||||
|         check('et?', [], 'str, bytes, bytearray or None') | ||||
|         check('et#', [], 'str, bytes or bytearray') | ||||
|         check('et#?', [], 'str, bytes, bytearray or None') | ||||
|         check('w*', [], 'read-write bytes-like object') | ||||
|         check('w*?', [], 'read-write bytes-like object or None') | ||||
|         check('S', [], 'bytes') | ||||
|         check('S?', [], 'bytes or None') | ||||
|         check('U', [], 'str') | ||||
|         check('U?', [], 'str or None') | ||||
|         check('Y', [], 'bytearray') | ||||
|         check('Y?', [], 'bytearray or None') | ||||
|         check('(OO)', 42, '2-item tuple', 'int') | ||||
|         check('(OO)?', 42, '2-item tuple or None', 'int') | ||||
|         check('(OO)', (1, 2, 3), 'tuple of length 2', '3') | ||||
| 
 | ||||
|     def test_nullable(self): | ||||
|         parse = _testcapi.parse_tuple_and_keywords | ||||
| 
 | ||||
|         def check(format, arg, allows_none=False): | ||||
|             # Because some format units (such as y*) require cleanup, | ||||
|             # we force the parsing code to perform the cleanup by adding | ||||
|             # an argument that always fails. | ||||
|             # By checking for an exception, we ensure that the parsing | ||||
|             # of the first argument was successful. | ||||
|             self.assertRaises(OverflowError, parse, | ||||
|                               (arg, 256), {}, format + '?b', ['a', 'b']) | ||||
|             self.assertRaises(OverflowError, parse, | ||||
|                               (None, 256), {}, format + '?b', ['a', 'b']) | ||||
|             self.assertRaises(OverflowError, parse, | ||||
|                               (arg, 256), {}, format + 'b', ['a', 'b']) | ||||
|             self.assertRaises(OverflowError if allows_none else TypeError, parse, | ||||
|                               (None, 256), {}, format + 'b', ['a', 'b']) | ||||
| 
 | ||||
|         check('b', 42) | ||||
|         check('B', 42) | ||||
|         check('h', 42) | ||||
|         check('H', 42) | ||||
|         check('i', 42) | ||||
|         check('I', 42) | ||||
|         check('n', 42) | ||||
|         check('l', 42) | ||||
|         check('k', 42) | ||||
|         check('L', 42) | ||||
|         check('K', 42) | ||||
|         check('f', 2.5) | ||||
|         check('d', 2.5) | ||||
|         check('D', 2.5j) | ||||
|         check('c', b'a') | ||||
|         check('C', 'a') | ||||
|         check('p', True, allows_none=True) | ||||
|         check('y', b'buffer') | ||||
|         check('y*', b'buffer') | ||||
|         check('y#', b'buffer') | ||||
|         check('s', 'string') | ||||
|         check('s*', 'string') | ||||
|         check('s#', 'string') | ||||
|         check('z', 'string', allows_none=True) | ||||
|         check('z*', 'string', allows_none=True) | ||||
|         check('z#', 'string', allows_none=True) | ||||
|         check('w*', bytearray(b'buffer')) | ||||
|         check('U', 'string') | ||||
|         check('S', b'bytes') | ||||
|         check('Y', bytearray(b'bytearray')) | ||||
|         check('O', object, allows_none=True) | ||||
| 
 | ||||
|         check('(OO)', (1, 2)) | ||||
|         self.assertEqual(parse((((1, 2), 3),), {}, '((OO)?O)', ['a']), (1, 2, 3)) | ||||
|         self.assertEqual(parse(((None, 3),), {}, '((OO)?O)', ['a']), (NULL, NULL, 3)) | ||||
|         self.assertEqual(parse((((1, 2), 3),), {}, '((OO)O)', ['a']), (1, 2, 3)) | ||||
|         self.assertRaises(TypeError, parse, ((None, 3),), {}, '((OO)O)', ['a']) | ||||
| 
 | ||||
|         parse((None,), {}, 'es?', ['a']) | ||||
|         parse((None,), {}, 'es#?', ['a']) | ||||
|         parse((None,), {}, 'et?', ['a']) | ||||
|         parse((None,), {}, 'et#?', ['a']) | ||||
|         parse((None,), {}, 'O!?', ['a']) | ||||
|         parse((None,), {}, 'O&?', ['a']) | ||||
| 
 | ||||
|         # TODO: More tests for es?, es#?, et?, et#?, O!, O& | ||||
| 
 | ||||
|     @unittest.skipIf(_testinternalcapi is None, 'needs _testinternalcapi') | ||||
|     def test_gh_119213(self): | ||||
|         rc, out, err = script_helper.assert_python_ok("-c", """if True: | ||||
|  |  | |||
|  | @ -732,7 +732,7 @@ def test_tagname(self): | |||
|         m2.close() | ||||
|         m1.close() | ||||
| 
 | ||||
|         with self.assertRaisesRegex(TypeError, 'must be str or None'): | ||||
|         with self.assertRaisesRegex(TypeError, 'tagname'): | ||||
|             mmap.mmap(-1, 8, tagname=1) | ||||
| 
 | ||||
|     @cpython_only | ||||
|  |  | |||
|  | @ -2012,7 +2012,7 @@ interpreter. | |||
| .. nonce: ofI5Fl | ||||
| .. section: C API | ||||
| 
 | ||||
| Add support of nullable arguments in :c:func:`PyArg_Parse` and similar | ||||
| [Reverted in :gh:`136991`] Add support of nullable arguments in :c:func:`PyArg_Parse` and similar | ||||
| functions. Adding ``?`` after any format unit makes ``None`` be accepted as | ||||
| a value. | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| Revert support of nullable arguments in :c:func:`PyArg_Parse`. | ||||
|  | @ -3918,7 +3918,9 @@ _validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags) | |||
|         PyObject *name = Py_None; | ||||
|         PyObject *defval; | ||||
|         PyObject *typ; | ||||
|         if (!PyArg_ParseTuple(item, "i|U?O", &flag, &name, &defval)) { | ||||
|         if (!PyArg_ParseTuple(item, "i|OO", &flag, &name, &defval) || | ||||
|             !(name == Py_None || PyUnicode_Check(name))) | ||||
|         { | ||||
|             PyErr_SetString(PyExc_TypeError, | ||||
|                    "paramflags must be a sequence of (int [,string [,value]]) tuples"); | ||||
|             return 0; | ||||
|  | @ -3983,8 +3985,10 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds) | |||
|     void *handle; | ||||
|     PyObject *paramflags = NULL; | ||||
| 
 | ||||
|     if (!PyArg_ParseTuple(args, "O|O?", &ftuple, ¶mflags)) | ||||
|     if (!PyArg_ParseTuple(args, "O|O", &ftuple, ¶mflags)) | ||||
|         return NULL; | ||||
|     if (paramflags == Py_None) | ||||
|         paramflags = NULL; | ||||
| 
 | ||||
|     ftuple = PySequence_Tuple(ftuple); | ||||
|     if (!ftuple) | ||||
|  | @ -4116,8 +4120,10 @@ PyCFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds) | |||
|     GUID *iid = NULL; | ||||
|     Py_ssize_t iid_len = 0; | ||||
| 
 | ||||
|     if (!PyArg_ParseTuple(args, "is|O?z#", &index, &name, ¶mflags, &iid, &iid_len)) | ||||
|     if (!PyArg_ParseTuple(args, "is|Oz#", &index, &name, ¶mflags, &iid, &iid_len)) | ||||
|         return NULL; | ||||
|     if (paramflags == Py_None) | ||||
|         paramflags = NULL; | ||||
| 
 | ||||
|     ctypes_state *st = get_module_state_by_def(Py_TYPE(type)); | ||||
|     if (!_validate_paramflags(st, type, paramflags)) { | ||||
|  |  | |||
|  | @ -1415,11 +1415,14 @@ interp_get_config(PyObject *self, PyObject *args, PyObject *kwds) | |||
|     PyObject *idobj = NULL; | ||||
|     int restricted = 0; | ||||
|     if (!PyArg_ParseTupleAndKeywords(args, kwds, | ||||
|                                      "O?|$p:get_config", kwlist, | ||||
|                                      "O|$p:get_config", kwlist, | ||||
|                                      &idobj, &restricted)) | ||||
|     { | ||||
|         return NULL; | ||||
|     } | ||||
|     if (idobj == Py_None) { | ||||
|         idobj = NULL; | ||||
|     } | ||||
| 
 | ||||
|     int reqready = 0; | ||||
|     PyInterpreterState *interp = \ | ||||
|  | @ -1536,14 +1539,14 @@ capture_exception(PyObject *self, PyObject *args, PyObject *kwds) | |||
|     static char *kwlist[] = {"exc", NULL}; | ||||
|     PyObject *exc_arg = NULL; | ||||
|     if (!PyArg_ParseTupleAndKeywords(args, kwds, | ||||
|                                      "|O?:capture_exception", kwlist, | ||||
|                                      "|O:capture_exception", kwlist, | ||||
|                                      &exc_arg)) | ||||
|     { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     PyObject *exc = exc_arg; | ||||
|     if (exc == NULL) { | ||||
|     if (exc == NULL || exc == Py_None) { | ||||
|         exc = PyErr_GetRaisedException(); | ||||
|         if (exc == NULL) { | ||||
|             Py_RETURN_NONE; | ||||
|  |  | |||
|  | @ -1228,16 +1228,23 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |||
|     static char *kwlist[] = {"markers", "default", "encoder", "indent", "key_separator", "item_separator", "sort_keys", "skipkeys", "allow_nan", NULL}; | ||||
| 
 | ||||
|     PyEncoderObject *s; | ||||
|     PyObject *markers = Py_None, *defaultfn, *encoder, *indent, *key_separator; | ||||
|     PyObject *markers, *defaultfn, *encoder, *indent, *key_separator; | ||||
|     PyObject *item_separator; | ||||
|     int sort_keys, skipkeys, allow_nan; | ||||
| 
 | ||||
|     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!?OOOUUppp:make_encoder", kwlist, | ||||
|         &PyDict_Type, &markers, &defaultfn, &encoder, &indent, | ||||
|     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOUUppp:make_encoder", kwlist, | ||||
|         &markers, &defaultfn, &encoder, &indent, | ||||
|         &key_separator, &item_separator, | ||||
|         &sort_keys, &skipkeys, &allow_nan)) | ||||
|         return NULL; | ||||
| 
 | ||||
|     if (markers != Py_None && !PyDict_Check(markers)) { | ||||
|         PyErr_Format(PyExc_TypeError, | ||||
|                      "make_encoder() argument 1 must be dict or None, " | ||||
|                      "not %.200s", Py_TYPE(markers)->tp_name); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     s = (PyEncoderObject *)type->tp_alloc(type, 0); | ||||
|     if (s == NULL) | ||||
|         return NULL; | ||||
|  |  | |||
|  | @ -667,12 +667,12 @@ PyThreadHandleObject_join(PyObject *op, PyObject *args) | |||
|     PyThreadHandleObject *self = PyThreadHandleObject_CAST(op); | ||||
| 
 | ||||
|     PyObject *timeout_obj = NULL; | ||||
|     if (!PyArg_ParseTuple(args, "|O?:join", &timeout_obj)) { | ||||
|     if (!PyArg_ParseTuple(args, "|O:join", &timeout_obj)) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     PyTime_t timeout_ns = -1; | ||||
|     if (timeout_obj != NULL) { | ||||
|     if (timeout_obj != NULL && timeout_obj != Py_None) { | ||||
|         if (_PyTime_FromSecondsObject(&timeout_ns, timeout_obj, | ||||
|                                       _PyTime_ROUND_TIMEOUT) < 0) { | ||||
|             return NULL; | ||||
|  | @ -1945,10 +1945,10 @@ thread_PyThread_start_joinable_thread(PyObject *module, PyObject *fargs, | |||
|     PyObject *func = NULL; | ||||
|     int daemon = 1; | ||||
|     thread_module_state *state = get_thread_state(module); | ||||
|     PyObject *hobj = Py_None; | ||||
|     PyObject *hobj = NULL; | ||||
|     if (!PyArg_ParseTupleAndKeywords(fargs, fkwargs, | ||||
|                                      "O|O!?p:start_joinable_thread", keywords, | ||||
|                                      &func, state->thread_handle_type, &hobj, &daemon)) { | ||||
|                                      "O|Op:start_joinable_thread", keywords, | ||||
|                                      &func, &hobj, &daemon)) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|  | @ -1958,6 +1958,14 @@ thread_PyThread_start_joinable_thread(PyObject *module, PyObject *fargs, | |||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     if (hobj == NULL) { | ||||
|         hobj = Py_None; | ||||
|     } | ||||
|     else if (hobj != Py_None && !Py_IS_TYPE(hobj, state->thread_handle_type)) { | ||||
|         PyErr_SetString(PyExc_TypeError, "'handle' must be a _ThreadHandle"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     if (PySys_Audit("_thread.start_joinable_thread", "OiO", func, daemon, | ||||
|                     hobj) < 0) { | ||||
|         return NULL; | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ | |||
| #endif | ||||
| 
 | ||||
| #include <Python.h> | ||||
| #include "pycore_abstract.h"      // _Py_convert_optional_to_ssize_t() | ||||
| #include "pycore_bytesobject.h"   // _PyBytes_Find() | ||||
| #include "pycore_fileutils.h"     // _Py_stat_struct | ||||
| #include "pycore_weakref.h"       // FT_CLEAR_WEAKREFS() | ||||
|  | @ -515,7 +516,7 @@ mmap_read_method(PyObject *op, PyObject *args) | |||
|     mmap_object *self = mmap_object_CAST(op); | ||||
| 
 | ||||
|     CHECK_VALID(NULL); | ||||
|     if (!PyArg_ParseTuple(args, "|n?:read", &num_bytes)) | ||||
|     if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes)) | ||||
|         return NULL; | ||||
|     CHECK_VALID(NULL); | ||||
| 
 | ||||
|  | @ -1709,7 +1710,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) | |||
|     DWORD off_lo;       /* lower 32 bits of offset */ | ||||
|     DWORD size_hi;      /* upper 32 bits of size */ | ||||
|     DWORD size_lo;      /* lower 32 bits of size */ | ||||
|     PyObject *tagname = NULL; | ||||
|     PyObject *tagname = Py_None; | ||||
|     DWORD dwErr = 0; | ||||
|     int fileno; | ||||
|     HANDLE fh = 0; | ||||
|  | @ -1719,7 +1720,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) | |||
|                                 "tagname", | ||||
|                                 "access", "offset", NULL }; | ||||
| 
 | ||||
|     if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|U?iL", keywords, | ||||
|     if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|OiL", keywords, | ||||
|                                      &fileno, &map_size, | ||||
|                                      &tagname, &access, &offset)) { | ||||
|         return NULL; | ||||
|  | @ -1852,7 +1853,13 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) | |||
|     m_obj->weakreflist = NULL; | ||||
|     m_obj->exports = 0; | ||||
|     /* set the tag name */ | ||||
|     if (tagname != NULL) { | ||||
|     if (!Py_IsNone(tagname)) { | ||||
|         if (!PyUnicode_Check(tagname)) { | ||||
|             Py_DECREF(m_obj); | ||||
|             return PyErr_Format(PyExc_TypeError, "expected str or None for " | ||||
|                                 "'tagname', not %.200s", | ||||
|                                 Py_TYPE(tagname)->tp_name); | ||||
|         } | ||||
|         m_obj->tagname = PyUnicode_AsWideCharString(tagname, NULL); | ||||
|         if (m_obj->tagname == NULL) { | ||||
|             Py_DECREF(m_obj); | ||||
|  |  | |||
							
								
								
									
										253
									
								
								Python/getargs.c
									
										
									
									
									
								
							
							
						
						
									
										253
									
								
								Python/getargs.c
									
										
									
									
									
								
							|  | @ -1,8 +1,6 @@ | |||
| 
 | ||||
| /* New getargs implementation */ | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #define PY_CXX_CONST const | ||||
| #include "Python.h" | ||||
| #include "pycore_abstract.h"      // _PyNumber_Index() | ||||
|  | @ -468,12 +466,9 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|     const char *format = *p_format; | ||||
|     int i; | ||||
|     Py_ssize_t len; | ||||
|     bool nullable = false; | ||||
|     int istuple = PyTuple_Check(arg); | ||||
|     int mustbetuple = istuple; | ||||
| 
 | ||||
|     assert(*format == '('); | ||||
|     format++; | ||||
|     for (;;) { | ||||
|         int c = *format++; | ||||
|         if (c == '(') { | ||||
|  | @ -482,12 +477,8 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|             level++; | ||||
|         } | ||||
|         else if (c == ')') { | ||||
|             if (level == 0) { | ||||
|                 if (*format == '?') { | ||||
|                     nullable = true; | ||||
|                 } | ||||
|             if (level == 0) | ||||
|                 break; | ||||
|             } | ||||
|             level--; | ||||
|         } | ||||
|         else if (c == ':' || c == ';' || c == '\0') | ||||
|  | @ -524,13 +515,6 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (arg == Py_None && nullable) { | ||||
|         const char *msg = skipitem(p_format, p_va, flags); | ||||
|         if (msg != NULL) { | ||||
|             levels[0] = 0; | ||||
|         } | ||||
|         return msg; | ||||
|     } | ||||
|     if (istuple) { | ||||
|         /* fallthrough */ | ||||
|     } | ||||
|  | @ -539,9 +523,8 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|     { | ||||
|         levels[0] = 0; | ||||
|         PyOS_snprintf(msgbuf, bufsize, | ||||
|                       "must be %d-item tuple%s, not %.50s", | ||||
|                       "must be %d-item tuple, not %.50s", | ||||
|                   n, | ||||
|                       nullable ? " or None" : "", | ||||
|                   arg == Py_None ? "None" : Py_TYPE(arg)->tp_name); | ||||
|         return msgbuf; | ||||
|     } | ||||
|  | @ -579,7 +562,7 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|         return msgbuf; | ||||
|     } | ||||
| 
 | ||||
|     format = *p_format + 1; | ||||
|     format = *p_format; | ||||
|     for (i = 0; i < n; i++) { | ||||
|         const char *msg; | ||||
|         PyObject *item = PyTuple_GET_ITEM(arg, i); | ||||
|  | @ -594,10 +577,6 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     format++; | ||||
|     if (*format == '?') { | ||||
|         format++; | ||||
|     } | ||||
|     *p_format = format; | ||||
|     if (!istuple) { | ||||
|         Py_DECREF(arg); | ||||
|  | @ -616,8 +595,11 @@ convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|     const char *format = *p_format; | ||||
| 
 | ||||
|     if (*format == '(' /* ')' */) { | ||||
|         format++; | ||||
|         msg = converttuple(arg, &format, p_va, flags, levels, msgbuf, | ||||
|                            bufsize, freelist); | ||||
|         if (msg == NULL) | ||||
|             format++; | ||||
|     } | ||||
|     else { | ||||
|         msg = convertsimple(arg, &format, p_va, flags, | ||||
|  | @ -647,7 +629,7 @@ _PyArg_BadArgument(const char *fname, const char *displayname, | |||
| } | ||||
| 
 | ||||
| static const char * | ||||
| converterr(bool nullable, const char *expected, PyObject *arg, char *msgbuf, size_t bufsize) | ||||
| converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize) | ||||
| { | ||||
|     assert(expected != NULL); | ||||
|     assert(arg != NULL); | ||||
|  | @ -657,23 +639,20 @@ converterr(bool nullable, const char *expected, PyObject *arg, char *msgbuf, siz | |||
|     } | ||||
|     else { | ||||
|         PyOS_snprintf(msgbuf, bufsize, | ||||
|                       "must be %.50s%s, not %.50s", expected, | ||||
|                       nullable ? " or None" : "", | ||||
|                       "must be %.50s, not %.50s", expected, | ||||
|                       arg == Py_None ? "None" : Py_TYPE(arg)->tp_name); | ||||
|     } | ||||
|     return msgbuf; | ||||
| } | ||||
| 
 | ||||
| static const char * | ||||
| convertcharerr(bool nullable, const char *expected, const char *what, Py_ssize_t size, | ||||
| convertcharerr(const char *expected, const char *what, Py_ssize_t size, | ||||
|                char *msgbuf, size_t bufsize) | ||||
| { | ||||
|     assert(expected != NULL); | ||||
|     PyOS_snprintf(msgbuf, bufsize, | ||||
|                   "must be %.50s%s, not %.50s of length %zd", | ||||
|                   expected, | ||||
|                   nullable ? " or None" : "", | ||||
|                   what, size); | ||||
|                   "must be %.50s, not %.50s of length %zd", | ||||
|                   expected, what, size); | ||||
|     return msgbuf; | ||||
| } | ||||
| 
 | ||||
|  | @ -693,26 +672,15 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|               char *msgbuf, size_t bufsize, freelist_t *freelist) | ||||
| { | ||||
| #define RETURN_ERR_OCCURRED return msgbuf | ||||
| #define HANDLE_NULLABLE                 \ | ||||
|         if (*format == '?') {           \ | ||||
|             format++;                   \ | ||||
|             if (arg == Py_None) {       \ | ||||
|                 break;                  \ | ||||
|             }                           \ | ||||
|             nullable = true;            \ | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     const char *format = *p_format; | ||||
|     char c = *format++; | ||||
|     const char *sarg; | ||||
|     bool nullable = false; | ||||
| 
 | ||||
|     switch (c) { | ||||
| 
 | ||||
|     case 'b': { /* unsigned byte -- very short int */ | ||||
|         unsigned char *p = va_arg(*p_va, unsigned char *); | ||||
|         HANDLE_NULLABLE; | ||||
|         long ival = PyLong_AsLong(arg); | ||||
|         if (ival == -1 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -726,6 +694,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|                             "unsigned byte integer is greater than maximum"); | ||||
|             RETURN_ERR_OCCURRED; | ||||
|         } | ||||
|         else | ||||
|             *p = (unsigned char) ival; | ||||
|         break; | ||||
|     } | ||||
|  | @ -733,7 +702,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|     case 'B': {/* byte sized bitfield - both signed and unsigned
 | ||||
|                   values allowed */ | ||||
|         unsigned char *p = va_arg(*p_va, unsigned char *); | ||||
|         HANDLE_NULLABLE; | ||||
|         unsigned long ival = PyLong_AsUnsignedLongMask(arg); | ||||
|         if (ival == (unsigned long)-1 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -744,7 +712,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'h': {/* signed short int */ | ||||
|         short *p = va_arg(*p_va, short *); | ||||
|         HANDLE_NULLABLE; | ||||
|         long ival = PyLong_AsLong(arg); | ||||
|         if (ival == -1 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -766,7 +733,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|     case 'H': { /* short int sized bitfield, both signed and
 | ||||
|                    unsigned allowed */ | ||||
|         unsigned short *p = va_arg(*p_va, unsigned short *); | ||||
|         HANDLE_NULLABLE; | ||||
|         unsigned long ival = PyLong_AsUnsignedLongMask(arg); | ||||
|         if (ival == (unsigned long)-1 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -777,7 +743,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'i': {/* signed int */ | ||||
|         int *p = va_arg(*p_va, int *); | ||||
|         HANDLE_NULLABLE; | ||||
|         long ival = PyLong_AsLong(arg); | ||||
|         if (ival == -1 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -799,7 +764,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|     case 'I': { /* int sized bitfield, both signed and
 | ||||
|                    unsigned allowed */ | ||||
|         unsigned int *p = va_arg(*p_va, unsigned int *); | ||||
|         HANDLE_NULLABLE; | ||||
|         unsigned long ival = PyLong_AsUnsignedLongMask(arg); | ||||
|         if (ival == (unsigned long)-1 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -812,7 +776,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|     { | ||||
|         PyObject *iobj; | ||||
|         Py_ssize_t *p = va_arg(*p_va, Py_ssize_t *); | ||||
|         HANDLE_NULLABLE; | ||||
|         Py_ssize_t ival = -1; | ||||
|         iobj = _PyNumber_Index(arg); | ||||
|         if (iobj != NULL) { | ||||
|  | @ -826,7 +789,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|     } | ||||
|     case 'l': {/* long int */ | ||||
|         long *p = va_arg(*p_va, long *); | ||||
|         HANDLE_NULLABLE; | ||||
|         long ival = PyLong_AsLong(arg); | ||||
|         if (ival == -1 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -837,10 +799,9 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'k': { /* long sized bitfield */ | ||||
|         unsigned long *p = va_arg(*p_va, unsigned long *); | ||||
|         HANDLE_NULLABLE; | ||||
|         unsigned long ival; | ||||
|         if (!PyIndex_Check(arg)) { | ||||
|             return converterr(nullable, "int", arg, msgbuf, bufsize); | ||||
|             return converterr("int", arg, msgbuf, bufsize); | ||||
|         } | ||||
|         ival = PyLong_AsUnsignedLongMask(arg); | ||||
|         if (ival == (unsigned long)(long)-1 && PyErr_Occurred()) { | ||||
|  | @ -852,7 +813,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'L': {/* long long */ | ||||
|         long long *p = va_arg( *p_va, long long * ); | ||||
|         HANDLE_NULLABLE; | ||||
|         long long ival = PyLong_AsLongLong(arg); | ||||
|         if (ival == (long long)-1 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -863,10 +823,9 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'K': { /* long long sized bitfield */ | ||||
|         unsigned long long *p = va_arg(*p_va, unsigned long long *); | ||||
|         HANDLE_NULLABLE; | ||||
|         unsigned long long ival; | ||||
|         if (!PyIndex_Check(arg)) { | ||||
|             return converterr(nullable, "int", arg, msgbuf, bufsize); | ||||
|             return converterr("int", arg, msgbuf, bufsize); | ||||
|         } | ||||
|         ival = PyLong_AsUnsignedLongLongMask(arg); | ||||
|         if (ival == (unsigned long long)(long long)-1 && PyErr_Occurred()) { | ||||
|  | @ -878,7 +837,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'f': {/* float */ | ||||
|         float *p = va_arg(*p_va, float *); | ||||
|         HANDLE_NULLABLE; | ||||
|         double dval = PyFloat_AsDouble(arg); | ||||
|         if (dval == -1.0 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -889,7 +847,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'd': {/* double */ | ||||
|         double *p = va_arg(*p_va, double *); | ||||
|         HANDLE_NULLABLE; | ||||
|         double dval = PyFloat_AsDouble(arg); | ||||
|         if (dval == -1.0 && PyErr_Occurred()) | ||||
|             RETURN_ERR_OCCURRED; | ||||
|  | @ -900,7 +857,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'D': {/* complex double */ | ||||
|         Py_complex *p = va_arg(*p_va, Py_complex *); | ||||
|         HANDLE_NULLABLE; | ||||
|         Py_complex cval; | ||||
|         cval = PyComplex_AsCComplex(arg); | ||||
|         if (PyErr_Occurred()) | ||||
|  | @ -912,10 +868,9 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'c': {/* char */ | ||||
|         char *p = va_arg(*p_va, char *); | ||||
|         HANDLE_NULLABLE; | ||||
|         if (PyBytes_Check(arg)) { | ||||
|             if (PyBytes_GET_SIZE(arg) != 1) { | ||||
|                 return convertcharerr(nullable, "a byte string of length 1", | ||||
|                 return convertcharerr("a byte string of length 1", | ||||
|                                       "a bytes object", PyBytes_GET_SIZE(arg), | ||||
|                                       msgbuf, bufsize); | ||||
|             } | ||||
|  | @ -923,28 +878,27 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|         } | ||||
|         else if (PyByteArray_Check(arg)) { | ||||
|             if (PyByteArray_GET_SIZE(arg) != 1) { | ||||
|                 return convertcharerr(nullable, "a byte string of length 1", | ||||
|                 return convertcharerr("a byte string of length 1", | ||||
|                                       "a bytearray object", PyByteArray_GET_SIZE(arg), | ||||
|                                       msgbuf, bufsize); | ||||
|             } | ||||
|             *p = PyByteArray_AS_STRING(arg)[0]; | ||||
|         } | ||||
|         else | ||||
|             return converterr(nullable, "a byte string of length 1", arg, msgbuf, bufsize); | ||||
|             return converterr("a byte string of length 1", arg, msgbuf, bufsize); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     case 'C': {/* unicode char */ | ||||
|         int *p = va_arg(*p_va, int *); | ||||
|         HANDLE_NULLABLE; | ||||
|         int kind; | ||||
|         const void *data; | ||||
| 
 | ||||
|         if (!PyUnicode_Check(arg)) | ||||
|             return converterr(nullable, "a unicode character", arg, msgbuf, bufsize); | ||||
|             return converterr("a unicode character", arg, msgbuf, bufsize); | ||||
| 
 | ||||
|         if (PyUnicode_GET_LENGTH(arg) != 1) { | ||||
|             return convertcharerr(nullable, "a unicode character", | ||||
|             return convertcharerr("a unicode character", | ||||
|                                   "a string", PyUnicode_GET_LENGTH(arg), | ||||
|                                   msgbuf, bufsize); | ||||
|         } | ||||
|  | @ -957,7 +911,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'p': {/* boolean *p*redicate */ | ||||
|         int *p = va_arg(*p_va, int *); | ||||
|         HANDLE_NULLABLE; | ||||
|         int val = PyObject_IsTrue(arg); | ||||
|         if (val > 0) | ||||
|             *p = 1; | ||||
|  | @ -976,31 +929,24 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|         const char *buf; | ||||
|         Py_ssize_t count; | ||||
|         if (*format == '*') { | ||||
|             format++; | ||||
|             HANDLE_NULLABLE; | ||||
|             if (getbuffer(arg, (Py_buffer*)p, &buf) < 0) | ||||
|                 return converterr(nullable, buf, arg, msgbuf, bufsize); | ||||
|                 return converterr(buf, arg, msgbuf, bufsize); | ||||
|             format++; | ||||
|             if (addcleanup(p, freelist, cleanup_buffer)) { | ||||
|                 return converterr( | ||||
|                     nullable, "(cleanup problem)", | ||||
|                     "(cleanup problem)", | ||||
|                     arg, msgbuf, bufsize); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|         else if (*format == '#') { | ||||
|         count = convertbuffer(arg, (const void **)p, &buf); | ||||
|         if (count < 0) | ||||
|             return converterr(buf, arg, msgbuf, bufsize); | ||||
|         if (*format == '#') { | ||||
|             Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); | ||||
|             format++; | ||||
|             HANDLE_NULLABLE; | ||||
|             count = convertbuffer(arg, (const void **)p, &buf); | ||||
|             if (count < 0) | ||||
|                 return converterr(nullable, buf, arg, msgbuf, bufsize); | ||||
|             *psize = count; | ||||
|         } | ||||
|         else { | ||||
|             HANDLE_NULLABLE; | ||||
|             count = convertbuffer(arg, (const void **)p, &buf); | ||||
|             if (count < 0) | ||||
|                 return converterr(nullable, buf, arg, msgbuf, bufsize); | ||||
|             format++; | ||||
|         } else { | ||||
|             if (strlen(*p) != (size_t)count) { | ||||
|                 PyErr_SetString(PyExc_ValueError, "embedded null byte"); | ||||
|                 RETURN_ERR_OCCURRED; | ||||
|  | @ -1016,35 +962,32 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|             /* "s*" or "z*" */ | ||||
|             Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *); | ||||
| 
 | ||||
|             format++; | ||||
|             HANDLE_NULLABLE; | ||||
|             if (c == 'z' && arg == Py_None) | ||||
|                 PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0); | ||||
|             else if (PyUnicode_Check(arg)) { | ||||
|                 Py_ssize_t len; | ||||
|                 sarg = PyUnicode_AsUTF8AndSize(arg, &len); | ||||
|                 if (sarg == NULL) | ||||
|                     return converterr(nullable, CONV_UNICODE, | ||||
|                     return converterr(CONV_UNICODE, | ||||
|                                       arg, msgbuf, bufsize); | ||||
|                 PyBuffer_FillInfo(p, arg, (void *)sarg, len, 1, 0); | ||||
|             } | ||||
|             else { /* any bytes-like object */ | ||||
|                 const char *buf; | ||||
|                 if (getbuffer(arg, p, &buf) < 0) | ||||
|                     return converterr(nullable, buf, arg, msgbuf, bufsize); | ||||
|                     return converterr(buf, arg, msgbuf, bufsize); | ||||
|             } | ||||
|             if (addcleanup(p, freelist, cleanup_buffer)) { | ||||
|                 return converterr( | ||||
|                     nullable, "(cleanup problem)", | ||||
|                     "(cleanup problem)", | ||||
|                     arg, msgbuf, bufsize); | ||||
|             } | ||||
|             format++; | ||||
|         } else if (*format == '#') { /* a string or read-only bytes-like object */ | ||||
|             /* "s#" or "z#" */ | ||||
|             const void **p = (const void **)va_arg(*p_va, const char **); | ||||
|             Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); | ||||
| 
 | ||||
|             format++; | ||||
|             HANDLE_NULLABLE; | ||||
|             if (c == 'z' && arg == Py_None) { | ||||
|                 *p = NULL; | ||||
|                 *psize = 0; | ||||
|  | @ -1053,7 +996,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|                 Py_ssize_t len; | ||||
|                 sarg = PyUnicode_AsUTF8AndSize(arg, &len); | ||||
|                 if (sarg == NULL) | ||||
|                     return converterr(nullable, CONV_UNICODE, | ||||
|                     return converterr(CONV_UNICODE, | ||||
|                                       arg, msgbuf, bufsize); | ||||
|                 *p = sarg; | ||||
|                 *psize = len; | ||||
|  | @ -1063,22 +1006,22 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|                 const char *buf; | ||||
|                 Py_ssize_t count = convertbuffer(arg, p, &buf); | ||||
|                 if (count < 0) | ||||
|                     return converterr(nullable, buf, arg, msgbuf, bufsize); | ||||
|                     return converterr(buf, arg, msgbuf, bufsize); | ||||
|                 *psize = count; | ||||
|             } | ||||
|             format++; | ||||
|         } else { | ||||
|             /* "s" or "z" */ | ||||
|             const char **p = va_arg(*p_va, const char **); | ||||
|             Py_ssize_t len; | ||||
|             sarg = NULL; | ||||
| 
 | ||||
|             HANDLE_NULLABLE; | ||||
|             if (c == 'z' && arg == Py_None) | ||||
|                 *p = NULL; | ||||
|             else if (PyUnicode_Check(arg)) { | ||||
|                 sarg = PyUnicode_AsUTF8AndSize(arg, &len); | ||||
|                 if (sarg == NULL) | ||||
|                     return converterr(nullable, CONV_UNICODE, | ||||
|                     return converterr(CONV_UNICODE, | ||||
|                                       arg, msgbuf, bufsize); | ||||
|                 if (strlen(sarg) != (size_t)len) { | ||||
|                     PyErr_SetString(PyExc_ValueError, "embedded null character"); | ||||
|  | @ -1087,7 +1030,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|                 *p = sarg; | ||||
|             } | ||||
|             else | ||||
|                 return converterr(c == 'z' || nullable, "str", | ||||
|                 return converterr(c == 'z' ? "str or None" : "str", | ||||
|                                   arg, msgbuf, bufsize); | ||||
|         } | ||||
|         break; | ||||
|  | @ -1116,14 +1059,48 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|             recode_strings = 0; | ||||
|         else | ||||
|             return converterr( | ||||
|                 nullable, "(unknown parser marker combination)", | ||||
|                 "(unknown parser marker combination)", | ||||
|                 arg, msgbuf, bufsize); | ||||
|         buffer = (char **)va_arg(*p_va, char **); | ||||
|         format++; | ||||
|         if (buffer == NULL) | ||||
|             return converterr(nullable, "(buffer is NULL)", | ||||
|             return converterr("(buffer is NULL)", | ||||
|                               arg, msgbuf, bufsize); | ||||
|         Py_ssize_t *psize = NULL; | ||||
| 
 | ||||
|         /* Encode object */ | ||||
|         if (!recode_strings && | ||||
|             (PyBytes_Check(arg) || PyByteArray_Check(arg))) { | ||||
|             s = Py_NewRef(arg); | ||||
|             if (PyBytes_Check(arg)) { | ||||
|                 size = PyBytes_GET_SIZE(s); | ||||
|                 ptr = PyBytes_AS_STRING(s); | ||||
|             } | ||||
|             else { | ||||
|                 size = PyByteArray_GET_SIZE(s); | ||||
|                 ptr = PyByteArray_AS_STRING(s); | ||||
|             } | ||||
|         } | ||||
|         else if (PyUnicode_Check(arg)) { | ||||
|             /* Encode object; use default error handling */ | ||||
|             s = PyUnicode_AsEncodedString(arg, | ||||
|                                           encoding, | ||||
|                                           NULL); | ||||
|             if (s == NULL) | ||||
|                 return converterr("(encoding failed)", | ||||
|                                   arg, msgbuf, bufsize); | ||||
|             assert(PyBytes_Check(s)); | ||||
|             size = PyBytes_GET_SIZE(s); | ||||
|             ptr = PyBytes_AS_STRING(s); | ||||
|             if (ptr == NULL) | ||||
|                 ptr = ""; | ||||
|         } | ||||
|         else { | ||||
|             return converterr( | ||||
|                 recode_strings ? "str" : "str, bytes or bytearray", | ||||
|                 arg, msgbuf, bufsize); | ||||
|         } | ||||
| 
 | ||||
|         /* Write output; output is guaranteed to be 0-terminated */ | ||||
|         if (*format == '#') { | ||||
|             /* Using buffer length parameter '#':
 | ||||
| 
 | ||||
|  | @ -1146,55 +1123,15 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|                trailing 0-byte | ||||
| 
 | ||||
|             */ | ||||
|             psize = va_arg(*p_va, Py_ssize_t*); | ||||
|             Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); | ||||
| 
 | ||||
|             format++; | ||||
|             if (psize == NULL) { | ||||
|                 Py_DECREF(s); | ||||
|                 return converterr( | ||||
|                     nullable, "(buffer_len is NULL)", | ||||
|                     "(buffer_len is NULL)", | ||||
|                     arg, msgbuf, bufsize); | ||||
|             } | ||||
|         } | ||||
|         HANDLE_NULLABLE; | ||||
| 
 | ||||
|         /* Encode object */ | ||||
|         if (!recode_strings && | ||||
|             (PyBytes_Check(arg) || PyByteArray_Check(arg))) { | ||||
|             s = Py_NewRef(arg); | ||||
|             if (PyBytes_Check(arg)) { | ||||
|                 size = PyBytes_GET_SIZE(s); | ||||
|                 ptr = PyBytes_AS_STRING(s); | ||||
|             } | ||||
|             else { | ||||
|                 size = PyByteArray_GET_SIZE(s); | ||||
|                 ptr = PyByteArray_AS_STRING(s); | ||||
|             } | ||||
|         } | ||||
|         else if (PyUnicode_Check(arg)) { | ||||
|             /* Encode object; use default error handling */ | ||||
|             s = PyUnicode_AsEncodedString(arg, | ||||
|                                           encoding, | ||||
|                                           NULL); | ||||
|             if (s == NULL) | ||||
|                 return converterr(nullable, "(encoding failed)", | ||||
|                                   arg, msgbuf, bufsize); | ||||
|             assert(PyBytes_Check(s)); | ||||
|             size = PyBytes_GET_SIZE(s); | ||||
|             ptr = PyBytes_AS_STRING(s); | ||||
|             if (ptr == NULL) | ||||
|                 ptr = ""; | ||||
|         } | ||||
|         else { | ||||
|             return converterr( | ||||
|                 nullable, | ||||
|                 recode_strings ? "str" | ||||
|                 : nullable ? "str, bytes, bytearray" | ||||
|                 : "str, bytes or bytearray", | ||||
|                 arg, msgbuf, bufsize); | ||||
|         } | ||||
| 
 | ||||
|         /* Write output; output is guaranteed to be 0-terminated */ | ||||
|         if (psize != NULL) { | ||||
|             if (*buffer == NULL) { | ||||
|                 *buffer = PyMem_NEW(char, size + 1); | ||||
|                 if (*buffer == NULL) { | ||||
|  | @ -1205,7 +1142,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|                 if (addcleanup(buffer, freelist, cleanup_ptr)) { | ||||
|                     Py_DECREF(s); | ||||
|                     return converterr( | ||||
|                         nullable, "(cleanup problem)", | ||||
|                         "(cleanup problem)", | ||||
|                         arg, msgbuf, bufsize); | ||||
|                 } | ||||
|             } else { | ||||
|  | @ -1239,7 +1176,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|             if ((Py_ssize_t)strlen(ptr) != size) { | ||||
|                 Py_DECREF(s); | ||||
|                 return converterr( | ||||
|                     nullable, "encoded string without null bytes", | ||||
|                     "encoded string without null bytes", | ||||
|                     arg, msgbuf, bufsize); | ||||
|             } | ||||
|             *buffer = PyMem_NEW(char, size + 1); | ||||
|  | @ -1250,7 +1187,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|             } | ||||
|             if (addcleanup(buffer, freelist, cleanup_ptr)) { | ||||
|                 Py_DECREF(s); | ||||
|                 return converterr(nullable, "(cleanup problem)", | ||||
|                 return converterr("(cleanup problem)", | ||||
|                                 arg, msgbuf, bufsize); | ||||
|             } | ||||
|             memcpy(*buffer, ptr, size+1); | ||||
|  | @ -1261,32 +1198,29 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|     case 'S': { /* PyBytes object */ | ||||
|         PyObject **p = va_arg(*p_va, PyObject **); | ||||
|         HANDLE_NULLABLE; | ||||
|         if (PyBytes_Check(arg)) | ||||
|             *p = arg; | ||||
|         else | ||||
|             return converterr(nullable, "bytes", arg, msgbuf, bufsize); | ||||
|             return converterr("bytes", arg, msgbuf, bufsize); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     case 'Y': { /* PyByteArray object */ | ||||
|         PyObject **p = va_arg(*p_va, PyObject **); | ||||
|         HANDLE_NULLABLE; | ||||
|         if (PyByteArray_Check(arg)) | ||||
|             *p = arg; | ||||
|         else | ||||
|             return converterr(nullable, "bytearray", arg, msgbuf, bufsize); | ||||
|             return converterr("bytearray", arg, msgbuf, bufsize); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     case 'U': { /* PyUnicode object */ | ||||
|         PyObject **p = va_arg(*p_va, PyObject **); | ||||
|         HANDLE_NULLABLE; | ||||
|         if (PyUnicode_Check(arg)) { | ||||
|             *p = arg; | ||||
|         } | ||||
|         else | ||||
|             return converterr(nullable, "str", arg, msgbuf, bufsize); | ||||
|             return converterr("str", arg, msgbuf, bufsize); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|  | @ -1297,11 +1231,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|             type = va_arg(*p_va, PyTypeObject*); | ||||
|             p = va_arg(*p_va, PyObject **); | ||||
|             format++; | ||||
|             HANDLE_NULLABLE; | ||||
|             if (PyType_IsSubtype(Py_TYPE(arg), type)) | ||||
|                 *p = arg; | ||||
|             else | ||||
|                 return converterr(nullable, type->tp_name, arg, msgbuf, bufsize); | ||||
|                 return converterr(type->tp_name, arg, msgbuf, bufsize); | ||||
| 
 | ||||
|         } | ||||
|         else if (*format == '&') { | ||||
|  | @ -1310,18 +1243,16 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
|             void *addr = va_arg(*p_va, void *); | ||||
|             int res; | ||||
|             format++; | ||||
|             HANDLE_NULLABLE; | ||||
|             if (! (res = (*convert)(arg, addr))) | ||||
|                 return converterr(nullable, "(unspecified)", | ||||
|                 return converterr("(unspecified)", | ||||
|                                   arg, msgbuf, bufsize); | ||||
|             if (res == Py_CLEANUP_SUPPORTED && | ||||
|                 addcleanup(addr, freelist, convert) == -1) | ||||
|                 return converterr(nullable, "(cleanup problem)", | ||||
|                 return converterr("(cleanup problem)", | ||||
|                                 arg, msgbuf, bufsize); | ||||
|         } | ||||
|         else { | ||||
|             p = va_arg(*p_va, PyObject **); | ||||
|             HANDLE_NULLABLE; | ||||
|             *p = arg; | ||||
|         } | ||||
|         break; | ||||
|  | @ -1333,30 +1264,29 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, | |||
| 
 | ||||
|         if (*format != '*') | ||||
|             return converterr( | ||||
|                 nullable, "(invalid use of 'w' format character)", | ||||
|                 "(invalid use of 'w' format character)", | ||||
|                 arg, msgbuf, bufsize); | ||||
|         format++; | ||||
|         HANDLE_NULLABLE; | ||||
| 
 | ||||
|         /* Caller is interested in Py_buffer, and the object supports it
 | ||||
|            directly. The request implicitly asks for PyBUF_SIMPLE, so the | ||||
|            result is C-contiguous with format 'B'. */ | ||||
|         if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { | ||||
|             PyErr_Clear(); | ||||
|             return converterr(nullable, "read-write bytes-like object", | ||||
|             return converterr("read-write bytes-like object", | ||||
|                               arg, msgbuf, bufsize); | ||||
|         } | ||||
|         assert(PyBuffer_IsContiguous((Py_buffer *)p, 'C')); | ||||
|         if (addcleanup(p, freelist, cleanup_buffer)) { | ||||
|             return converterr( | ||||
|                 nullable, "(cleanup problem)", | ||||
|                 "(cleanup problem)", | ||||
|                 arg, msgbuf, bufsize); | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     default: | ||||
|         return converterr(nullable, "(impossible<bad format char>)", arg, msgbuf, bufsize); | ||||
|         return converterr("(impossible<bad format char>)", arg, msgbuf, bufsize); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|  | @ -2751,9 +2681,6 @@ skipitem(const char **p_format, va_list *p_va, int flags) | |||
|         return "impossible<bad format char>"; | ||||
| 
 | ||||
|     } | ||||
|     if (*format == '?') { | ||||
|         format++; | ||||
|     } | ||||
| 
 | ||||
|     *p_format = format; | ||||
|     return NULL; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Serhiy Storchaka
						Serhiy Storchaka