https://bugs.gentoo.org/921637 https://github.com/swig/swig/issues/2778 https://github.com/pygraphviz/pygraphviz/commit/6ecae22cc382407652f9d3b57e9da89a3a03043b From 6ecae22cc382407652f9d3b57e9da89a3a03043b Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Fri, 26 Jan 2024 00:52:44 +0000 Subject: [PATCH] Remove outdated pystrings.swg (#508) Remove pystring.swg - a very ancient copy from SWIG which does not compile when using swig-4.2.0. Instead SWIG's version of pystrings.swg that is kept up to date in SWIG is used. SWIG_PYTHON_STRICT_BYTE_CHAR needs to be defined in order to maintain the current behaviour of only allowing Python 3 byte type instead of Python 3 string type as input. As the output of swig is in graphviz_wrap.c and is committed to the repo, the updates committed in this file (keeping the current swig-4.1.1 version). A later commit could update it to swig-4.2.0. Fixes build problems on Fedora where SWIG_Python_str_AsChar no longer exists, as reported at https://github.com/swig/swig/issues/2778. --- pygraphviz/graphviz.i | 4 ++ pygraphviz/graphviz_wrap.c | 106 ++++++++++++++++++++++++++++--------- pystrings.swg | 86 ------------------------------ 3 files changed, 84 insertions(+), 112 deletions(-) delete mode 100644 pystrings.swg diff --git a/pygraphviz/graphviz.i b/pygraphviz/graphviz.i index c63eb2d3..d7c49330 100644 --- a/pygraphviz/graphviz.i +++ b/pygraphviz/graphviz.i @@ -1,5 +1,9 @@ %module graphviz +%begin %{ +#define SWIG_PYTHON_STRICT_BYTE_CHAR +%} + %{ #include "graphviz/cgraph.h" #include "graphviz/gvc.h" diff --git a/pygraphviz/graphviz_wrap.c b/pygraphviz/graphviz_wrap.c index 8f4d3a62..cb06da79 100644 --- a/pygraphviz/graphviz_wrap.c +++ b/pygraphviz/graphviz_wrap.c @@ -6,6 +6,9 @@ * the SWIG interface file instead. * ----------------------------------------------------------------------------- */ +#define SWIG_PYTHON_STRICT_BYTE_CHAR + + #define SWIG_VERSION 0x040101 #define SWIGPYTHON @@ -3038,49 +3041,96 @@ SWIGINTERN int SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) { #if PY_VERSION_HEX>=0x03000000 +#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) if (PyBytes_Check(obj)) #else + if (PyUnicode_Check(obj)) +#endif +#else if (PyString_Check(obj)) #endif { char *cstr; Py_ssize_t len; + int ret = SWIG_OK; #if PY_VERSION_HEX>=0x03000000 - PyBytes_AsStringAndSize(obj, &cstr, &len); - if(alloc) *alloc = SWIG_NEWOBJ; +#if !defined(SWIG_PYTHON_STRICT_BYTE_CHAR) + if (!alloc && cptr) { + /* We can't allow converting without allocation, since the internal + representation of string in Python 3 is UCS-2/UCS-4 but we require + a UTF-8 representation. + TODO(bhy) More detailed explanation */ + return SWIG_RuntimeError; + } + obj = PyUnicode_AsUTF8String(obj); + if (!obj) + return SWIG_TypeError; + if (alloc) + *alloc = SWIG_NEWOBJ; +#endif + if (PyBytes_AsStringAndSize(obj, &cstr, &len) == -1) + return SWIG_TypeError; #else - PyString_AsStringAndSize(obj, &cstr, &len); + if (PyString_AsStringAndSize(obj, &cstr, &len) == -1) + return SWIG_TypeError; #endif if (cptr) { if (alloc) { - /* - In python the user should not be able to modify the inner - string representation. To warranty that, if you define - SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string - buffer is always returned. - - The default behavior is just to return the pointer value, - so, be careful. - */ -#if defined(SWIG_PYTHON_SAFE_CSTRINGS) - if (*alloc != SWIG_OLDOBJ) -#else - if (*alloc == SWIG_NEWOBJ) -#endif - { - *cptr = (char *)memcpy(malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); - *alloc = SWIG_NEWOBJ; - } - else { + if (*alloc == SWIG_NEWOBJ) { + *cptr = (char *)memcpy(malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + *alloc = SWIG_NEWOBJ; + } else { *cptr = cstr; *alloc = SWIG_OLDOBJ; } } else { +#if PY_VERSION_HEX>=0x03000000 +#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) + *cptr = PyBytes_AsString(obj); +#else + assert(0); /* Should never reach here with Unicode strings in Python 3 */ +#endif +#else *cptr = SWIG_Python_str_AsChar(obj); + if (!*cptr) + ret = SWIG_TypeError; +#endif } } if (psize) *psize = len + 1; - return SWIG_OK; +#if PY_VERSION_HEX>=0x03000000 && !defined(SWIG_PYTHON_STRICT_BYTE_CHAR) + Py_XDECREF(obj); +#endif + return ret; } else { +#if defined(SWIG_PYTHON_2_UNICODE) +#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) +#error "Cannot use both SWIG_PYTHON_2_UNICODE and SWIG_PYTHON_STRICT_BYTE_CHAR at once" +#endif +#if PY_VERSION_HEX<0x03000000 + if (PyUnicode_Check(obj)) { + char *cstr; Py_ssize_t len; + if (!alloc && cptr) { + return SWIG_RuntimeError; + } + obj = PyUnicode_AsUTF8String(obj); + if (!obj) + return SWIG_TypeError; + if (PyString_AsStringAndSize(obj, &cstr, &len) != -1) { + if (cptr) { + if (alloc) *alloc = SWIG_NEWOBJ; + *cptr = (char *)memcpy(malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + } + if (psize) *psize = len + 1; + + Py_XDECREF(obj); + return SWIG_OK; + } else { + Py_XDECREF(obj); + } + } +#endif +#endif + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); if (pchar_descriptor) { void* vptr = 0; @@ -3311,13 +3361,17 @@ SWIG_FromCharPtrAndSize(const char* carray, size_t size) if (carray) { if (size > INT_MAX) { swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); - return pchar_descriptor ? + return pchar_descriptor ? SWIG_InternalNewPointerObj((char *)(carray), pchar_descriptor, 0) : SWIG_Py_Void(); } else { #if PY_VERSION_HEX >= 0x03000000 - return PyBytes_FromStringAndSize(carray, (int)(size)); +#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) + return PyBytes_FromStringAndSize(carray, (Py_ssize_t)(size)); +#else + return PyUnicode_DecodeUTF8(carray, (Py_ssize_t)(size), "surrogateescape"); +#endif #else - return PyString_FromStringAndSize(carray, (int)(size)); + return PyString_FromStringAndSize(carray, (Py_ssize_t)(size)); #endif } } else { diff --git a/pystrings.swg b/pystrings.swg deleted file mode 100644 index 7988a353..00000000 --- a/pystrings.swg +++ /dev/null @@ -1,86 +0,0 @@ -/* Fixed fragments for work with bytes in Python 3. */ - -%fragment("SWIG_AsCharPtrAndSize","header",fragment="SWIG_pchar_descriptor") { -SWIGINTERN int -SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) -{ -%#if PY_VERSION_HEX>=0x03000000 - if (PyBytes_Check(obj)) -%#else - if (PyString_Check(obj)) -%#endif - { - char *cstr; Py_ssize_t len; -%#if PY_VERSION_HEX>=0x03000000 - PyBytes_AsStringAndSize(obj, &cstr, &len); - if(alloc) *alloc = SWIG_NEWOBJ; -%#else - PyString_AsStringAndSize(obj, &cstr, &len); -%#endif - if (cptr) { - if (alloc) { - /* - In python the user should not be able to modify the inner - string representation. To warranty that, if you define - SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string - buffer is always returned. - - The default behavior is just to return the pointer value, - so, be careful. - */ -%#if defined(SWIG_PYTHON_SAFE_CSTRINGS) - if (*alloc != SWIG_OLDOBJ) -%#else - if (*alloc == SWIG_NEWOBJ) -%#endif - { - *cptr = %new_copy_array(cstr, len + 1, char); - *alloc = SWIG_NEWOBJ; - } - else { - *cptr = cstr; - *alloc = SWIG_OLDOBJ; - } - } else { - *cptr = SWIG_Python_str_AsChar(obj); - } - } - if (psize) *psize = len + 1; - return SWIG_OK; - } else { - swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); - if (pchar_descriptor) { - void* vptr = 0; - if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { - if (cptr) *cptr = (char *) vptr; - if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; - if (alloc) *alloc = SWIG_OLDOBJ; - return SWIG_OK; - } - } - } - return SWIG_TypeError; -} -} - -%fragment("SWIG_FromCharPtrAndSize","header",fragment="SWIG_pchar_descriptor") { -SWIGINTERNINLINE PyObject * -SWIG_FromCharPtrAndSize(const char* carray, size_t size) -{ - if (carray) { - if (size > INT_MAX) { - swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); - return pchar_descriptor ? - SWIG_InternalNewPointerObj(%const_cast(carray,char *), pchar_descriptor, 0) : SWIG_Py_Void(); - } else { -%#if PY_VERSION_HEX >= 0x03000000 - return PyBytes_FromStringAndSize(carray, %numeric_cast(size,int)); -%#else - return PyString_FromStringAndSize(carray, %numeric_cast(size,int)); -%#endif - } - } else { - return SWIG_Py_Void(); - } -} -}