On 5/29/16 2:30 AM, Michał Górny wrote:
> On Fri, 27 May 2016 10:26:44 -0400
> "Anthony G. Basile" <bas...@opensource.dyc.edu> wrote:
> 
>> From: "Anthony G. Basile" <bluen...@gentoo.org>
>>
>> The current method to check for a sane system locale is to use python's
>> ctypes.util.find_library() to construct a full library path to the
>> system libc.so and pass that path to ctypes.CDLL() so we can call
>> toupper() and tolower() directly.  However, this gets bogged down in
>> implementation details and fails with musl.
>>
>> We work around this design flaw in ctypes with a small python module
>> written in C which provides thin wrappers to toupper() and tolower(),
>> and only fall back on the current ctypes-based check when this module
>> is not available.
>>
>> This has been tested on glibc, uClibc and musl systems.
>>
>> X-Gentoo-bug: 571444
>> X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=571444
>>
>> Signed-off-by: Anthony G. Basile <bluen...@gentoo.org>
>> ---
>>  pym/portage/util/locale.py | 16 ++++++-----
>>  setup.py                   |  6 +++-
>>  src/portage_util_libc.c    | 70 
>> ++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 84 insertions(+), 8 deletions(-)
>>  create mode 100644 src/portage_util_libc.c
>>
>> diff --git a/pym/portage/util/locale.py b/pym/portage/util/locale.py
>> index 093eb86..5b09945 100644
>> --- a/pym/portage/util/locale.py
>> +++ b/pym/portage/util/locale.py
>> @@ -34,13 +34,15 @@ def _check_locale(silent):
>>      """
>>      The inner locale check function.
>>      """
>> -
>> -    libc_fn = find_library("c")
>> -    if libc_fn is None:
>> -            return None
>> -    libc = LoadLibrary(libc_fn)
>> -    if libc is None:
>> -            return None
>> +    try:
>> +            from portage.util import libc
>> +    except ImportError:
>> +            libc_fn = find_library("c")
>> +            if libc_fn is None:
>> +                    return None
>> +            libc = LoadLibrary(libc_fn)
>> +            if libc is None:
>> +                    return None
>>  
>>      lc = list(range(ord('a'), ord('z')+1))
>>      uc = list(range(ord('A'), ord('Z')+1))
>> diff --git a/setup.py b/setup.py
>> index 25429bc..5ca8156 100755
>> --- a/setup.py
>> +++ b/setup.py
>> @@ -47,7 +47,11 @@ x_scripts = {
>>  # Dictionary custom modules written in C/C++ here.  The structure is
>>  #   key   = module name
>>  #   value = list of C/C++ source code, path relative to top source directory
>> -x_c_helpers = {}
>> +x_c_helpers = {
>> +    'portage.util.libc' : [
>> +            'src/portage_util_libc.c',
>> +    ],
>> +}
>>  
>>  class x_build(build):
>>      """ Build command with extra build_man call. """
>> diff --git a/src/portage_util_libc.c b/src/portage_util_libc.c
>> new file mode 100644
>> index 0000000..00b09c2
>> --- /dev/null
>> +++ b/src/portage_util_libc.c
>> @@ -0,0 +1,70 @@
>> +/* Copyright 2005-2016 Gentoo Foundation
>> + * Distributed under the terms of the GNU General Public License v2
>> + */
>> +
>> +#include <Python.h>
>> +#include <stdlib.h>
>> +#include <ctype.h>
>> +
>> +static PyObject * _libc_tolower(PyObject *, PyObject *);
>> +static PyObject * _libc_toupper(PyObject *, PyObject *);
>> +
>> +static PyMethodDef LibcMethods[] = {
>> +    {"tolower", _libc_tolower, METH_VARARGS, "Convert to lower case using 
>> system locale."},
>> +    {"toupper", _libc_toupper, METH_VARARGS, "Convert to upper case using 
>> system locale."},
>> +    {NULL, NULL, 0, NULL}
>> +};
>> +
>> +#if PY_MAJOR_VERSION >= 3
>> +static struct PyModuleDef moduledef = {
>> +    PyModuleDef_HEAD_INIT,
>> +    "libc",                                                         /* 
>> m_name */
>> +    "Module for converting case using the system locale",           /* 
>> m_doc */
>> +    -1,                                                             /* 
>> m_size */
>> +    LibcMethods,                                                    /* 
>> m_methods */
>> +    NULL,                                                           /* 
>> m_reload */
>> +    NULL,                                                           /* 
>> m_traverse */
>> +    NULL,                                                           /* 
>> m_clear */
>> +    NULL,                                                           /* 
>> m_free */
>> +};
>> +#endif
>> +
>> +PyMODINIT_FUNC
> 
> Now you could call it nitpicking but since it decorates the function,
> it would be better to have it inside the #ifdef. Otherwise, people
> would think it's separate from that.

You mean repeat it twice?

> 
>> +
>> +#if PY_MAJOR_VERSION >= 3
>> +PyInit_libc(void)
>> +{
>> +    PyObject *m;
>> +    m = PyModule_Create(&moduledef);
>> +    return m;
>> +}
>> +#else
>> +initlibc(void)
>> +{
>> +    Py_InitModule("libc", LibcMethods);
>> +}
>> +#endif
>> +
>> +
>> +static PyObject *
>> +_libc_tolower(PyObject *self, PyObject *args)
>> +{
>> +    int c;
>> +
>> +    if (!PyArg_ParseTuple(args, "i", &c))
>> +            return NULL;
>> +
>> +    return Py_BuildValue("i", tolower(c));
>> +}
>> +
>> +
>> +static PyObject *
>> +_libc_toupper(PyObject *self, PyObject *args)
>> +{
>> +    int c;
>> +
>> +    if (!PyArg_ParseTuple(args, "i", &c))
>> +            return NULL;
>> +
>> +    return Py_BuildValue("i", toupper(c));
>> +}
> 
> Aside from that, it look nice and shiny now. Thanks a lot!

so what's the other stuff that could get put into this module that you
mentioned?

> 


-- 
Anthony G. Basile, Ph. D.
Chair of Information Technology
D'Youville College
Buffalo, NY 14201
(716) 829-8197

Reply via email to