diff options
author | Gregory P. Smith <greg@krypto.org> | 2019-05-29 18:46:58 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-29 18:46:58 (GMT) |
commit | 0c2f9305640f7655ba0cd5f478948b2763b376b3 (patch) | |
tree | eb5b39614be93083e883f7aeb6f3397d8d8b89c2 /Modules | |
parent | aacc77fbd77640a8f03638216fa09372cc21673d (diff) | |
download | cpython-0c2f9305640f7655ba0cd5f478948b2763b376b3.zip cpython-0c2f9305640f7655ba0cd5f478948b2763b376b3.tar.gz cpython-0c2f9305640f7655ba0cd5f478948b2763b376b3.tar.bz2 |
bpo-22385: Support output separators in hex methods. (#13578)
* bpo-22385: Support output separators in hex methods.
Also in binascii.hexlify aka b2a_hex.
The underlying implementation behind all hex generation in CPython uses the
same pystrhex.c implementation. This adds support to bytes, bytearray,
and memoryview objects.
The binascii module functions exist rather than being slated for deprecation
because they return bytes rather than requiring an intermediate step through a
str object.
This change was inspired by MicroPython which supports sep in its binascii
implementation (and does not yet support the .hex methods).
https://bugs.python.org/issue22385
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/binascii.c | 33 | ||||
-rw-r--r-- | Modules/clinic/binascii.c.h | 115 |
2 files changed, 123 insertions, 25 deletions
diff --git a/Modules/binascii.c b/Modules/binascii.c index d22ab7b..1c7dc35 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -1159,19 +1159,33 @@ binascii_crc32_impl(PyObject *module, Py_buffer *data, unsigned int crc) binascii.b2a_hex data: Py_buffer - / + sep: object = NULL + An optional single character or byte to separate hex bytes. + bytes_per_sep: int = 1 + How many bytes between separators. Positive values count from the + right, negative values count from the left. Hexadecimal representation of binary data. The return value is a bytes object. This function is also available as "hexlify()". + +Example: +>>> binascii.b2a_hex(b'\xb9\x01\xef') +b'b901ef' +>>> binascii.hexlify(b'\xb9\x01\xef', ':') +b'b9:01:ef' +>>> binascii.b2a_hex(b'\xb9\x01\xef', b'_', 2) +b'b9_01ef' [clinic start generated code]*/ static PyObject * -binascii_b2a_hex_impl(PyObject *module, Py_buffer *data) -/*[clinic end generated code: output=92fec1a95c9897a0 input=96423cfa299ff3b1]*/ +binascii_b2a_hex_impl(PyObject *module, Py_buffer *data, PyObject *sep, + int bytes_per_sep) +/*[clinic end generated code: output=a26937946a81d2c7 input=ec0ade6ba2e43543]*/ { - return _Py_strhex_bytes((const char *)data->buf, data->len); + return _Py_strhex_bytes_with_sep((const char *)data->buf, data->len, + sep, bytes_per_sep); } /*[clinic input] @@ -1179,14 +1193,17 @@ binascii.hexlify = binascii.b2a_hex Hexadecimal representation of binary data. -The return value is a bytes object. +The return value is a bytes object. This function is also +available as "b2a_hex()". [clinic start generated code]*/ static PyObject * -binascii_hexlify_impl(PyObject *module, Py_buffer *data) -/*[clinic end generated code: output=749e95e53c14880c input=2e3afae7f083f061]*/ +binascii_hexlify_impl(PyObject *module, Py_buffer *data, PyObject *sep, + int bytes_per_sep) +/*[clinic end generated code: output=d12aa1b001b15199 input=bc317bd4e241f76b]*/ { - return _Py_strhex_bytes((const char *)data->buf, data->len); + return _Py_strhex_bytes_with_sep((const char *)data->buf, data->len, + sep, bytes_per_sep); } /*[clinic input] diff --git a/Modules/clinic/binascii.c.h b/Modules/clinic/binascii.c.h index 4043d89..d485048 100644 --- a/Modules/clinic/binascii.c.h +++ b/Modules/clinic/binascii.c.h @@ -432,34 +432,78 @@ exit: } PyDoc_STRVAR(binascii_b2a_hex__doc__, -"b2a_hex($module, data, /)\n" +"b2a_hex($module, /, data, sep=None, bytes_per_sep=1)\n" "--\n" "\n" "Hexadecimal representation of binary data.\n" "\n" +" sep\n" +" An optional single character or byte to separate hex bytes.\n" +" bytes_per_sep\n" +" How many bytes between separators. Positive values count from the\n" +" right, negative values count from the left.\n" +"\n" "The return value is a bytes object. This function is also\n" -"available as \"hexlify()\"."); +"available as \"hexlify()\".\n" +"\n" +"Example:\n" +">>> binascii.b2a_hex(b\'\\xb9\\x01\\xef\')\n" +"b\'b901ef\'\n" +">>> binascii.hexlify(b\'\\xb9\\x01\\xef\', \':\')\n" +"b\'b9:01:ef\'\n" +">>> binascii.b2a_hex(b\'\\xb9\\x01\\xef\', b\'_\', 2)\n" +"b\'b9_01ef\'"); #define BINASCII_B2A_HEX_METHODDEF \ - {"b2a_hex", (PyCFunction)binascii_b2a_hex, METH_O, binascii_b2a_hex__doc__}, + {"b2a_hex", (PyCFunction)(void(*)(void))binascii_b2a_hex, METH_FASTCALL|METH_KEYWORDS, binascii_b2a_hex__doc__}, static PyObject * -binascii_b2a_hex_impl(PyObject *module, Py_buffer *data); +binascii_b2a_hex_impl(PyObject *module, Py_buffer *data, PyObject *sep, + int bytes_per_sep); static PyObject * -binascii_b2a_hex(PyObject *module, PyObject *arg) +binascii_b2a_hex(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + static const char * const _keywords[] = {"data", "sep", "bytes_per_sep", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "b2a_hex", 0}; + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; Py_buffer data = {NULL, NULL}; + PyObject *sep = NULL; + int bytes_per_sep = 1; - if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 3, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &data, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&data, 'C')) { - _PyArg_BadArgument("b2a_hex", 0, "contiguous buffer", arg); + _PyArg_BadArgument("b2a_hex", 1, "contiguous buffer", args[0]); goto exit; } - return_value = binascii_b2a_hex_impl(module, &data); + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + sep = args[1]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (PyFloat_Check(args[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + bytes_per_sep = _PyLong_AsInt(args[2]); + if (bytes_per_sep == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = binascii_b2a_hex_impl(module, &data, sep, bytes_per_sep); exit: /* Cleanup for data */ @@ -471,33 +515,70 @@ exit: } PyDoc_STRVAR(binascii_hexlify__doc__, -"hexlify($module, data, /)\n" +"hexlify($module, /, data, sep=None, bytes_per_sep=1)\n" "--\n" "\n" "Hexadecimal representation of binary data.\n" "\n" -"The return value is a bytes object."); +" sep\n" +" An optional single character or byte to separate hex bytes.\n" +" bytes_per_sep\n" +" How many bytes between separators. Positive values count from the\n" +" right, negative values count from the left.\n" +"\n" +"The return value is a bytes object. This function is also\n" +"available as \"b2a_hex()\"."); #define BINASCII_HEXLIFY_METHODDEF \ - {"hexlify", (PyCFunction)binascii_hexlify, METH_O, binascii_hexlify__doc__}, + {"hexlify", (PyCFunction)(void(*)(void))binascii_hexlify, METH_FASTCALL|METH_KEYWORDS, binascii_hexlify__doc__}, static PyObject * -binascii_hexlify_impl(PyObject *module, Py_buffer *data); +binascii_hexlify_impl(PyObject *module, Py_buffer *data, PyObject *sep, + int bytes_per_sep); static PyObject * -binascii_hexlify(PyObject *module, PyObject *arg) +binascii_hexlify(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + static const char * const _keywords[] = {"data", "sep", "bytes_per_sep", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "hexlify", 0}; + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; Py_buffer data = {NULL, NULL}; + PyObject *sep = NULL; + int bytes_per_sep = 1; - if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 3, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &data, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&data, 'C')) { - _PyArg_BadArgument("hexlify", 0, "contiguous buffer", arg); + _PyArg_BadArgument("hexlify", 1, "contiguous buffer", args[0]); goto exit; } - return_value = binascii_hexlify_impl(module, &data); + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + sep = args[1]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (PyFloat_Check(args[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + bytes_per_sep = _PyLong_AsInt(args[2]); + if (bytes_per_sep == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = binascii_hexlify_impl(module, &data, sep, bytes_per_sep); exit: /* Cleanup for data */ @@ -720,4 +801,4 @@ exit: return return_value; } -/*[clinic end generated code: output=a4a38e162605aca2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f7b8049edb130c63 input=a9049054013a1b77]*/ |