Gentoo Archives: gentoo-portage-dev

From: "Anthony G. Basile" <basile@××××××××××××××.edu>
To: gentoo-portage-dev@l.g.o
Cc: "Anthony G. Basile" <blueness@g.o>
Subject: [gentoo-portage-dev] [PATCH 3/3] pym/portage/util/locale.py: add a C module to help check locale
Date: Mon, 30 May 2016 19:24:41
Message-Id: 1464636264-31164-1-git-send-email-basile@opensource.dyc.edu
1 From: "Anthony G. Basile" <blueness@g.o>
2
3 The current method to check for a sane system locale is to use python's
4 ctypes.util.find_library() to construct a full library path to the
5 system libc.so and pass that path to ctypes.CDLL() so we can call
6 toupper() and tolower() directly. However, this gets bogged down in
7 implementation details and fails with musl.
8
9 We work around this design flaw in ctypes with a small python module
10 written in C which provides thin wrappers to toupper() and tolower(),
11 and only fall back on the current ctypes-based check when this module
12 is not available.
13
14 This has been tested on glibc, uClibc and musl systems.
15
16 X-Gentoo-bug: 571444
17 X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=571444
18
19 Signed-off-by: Anthony G. Basile <blueness@g.o>
20 ---
21 pym/portage/util/locale.py | 16 ++++++-----
22 setup.py | 6 +++-
23 src/portage_util_libc.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
24 3 files changed, 82 insertions(+), 8 deletions(-)
25 create mode 100644 src/portage_util_libc.c
26
27 diff --git a/pym/portage/util/locale.py b/pym/portage/util/locale.py
28 index 093eb86..5b09945 100644
29 --- a/pym/portage/util/locale.py
30 +++ b/pym/portage/util/locale.py
31 @@ -34,13 +34,15 @@ def _check_locale(silent):
32 """
33 The inner locale check function.
34 """
35 -
36 - libc_fn = find_library("c")
37 - if libc_fn is None:
38 - return None
39 - libc = LoadLibrary(libc_fn)
40 - if libc is None:
41 - return None
42 + try:
43 + from portage.util import libc
44 + except ImportError:
45 + libc_fn = find_library("c")
46 + if libc_fn is None:
47 + return None
48 + libc = LoadLibrary(libc_fn)
49 + if libc is None:
50 + return None
51
52 lc = list(range(ord('a'), ord('z')+1))
53 uc = list(range(ord('A'), ord('Z')+1))
54 diff --git a/setup.py b/setup.py
55 index 25429bc..5ca8156 100755
56 --- a/setup.py
57 +++ b/setup.py
58 @@ -47,7 +47,11 @@ x_scripts = {
59 # Dictionary custom modules written in C/C++ here. The structure is
60 # key = module name
61 # value = list of C/C++ source code, path relative to top source directory
62 -x_c_helpers = {}
63 +x_c_helpers = {
64 + 'portage.util.libc' : [
65 + 'src/portage_util_libc.c',
66 + ],
67 +}
68
69 class x_build(build):
70 """ Build command with extra build_man call. """
71 diff --git a/src/portage_util_libc.c b/src/portage_util_libc.c
72 new file mode 100644
73 index 0000000..977b954
74 --- /dev/null
75 +++ b/src/portage_util_libc.c
76 @@ -0,0 +1,68 @@
77 +/* Copyright 2005-2016 Gentoo Foundation
78 + * Distributed under the terms of the GNU General Public License v2
79 + */
80 +
81 +#include <Python.h>
82 +#include <stdlib.h>
83 +#include <ctype.h>
84 +
85 +static PyObject * _libc_tolower(PyObject *, PyObject *);
86 +static PyObject * _libc_toupper(PyObject *, PyObject *);
87 +
88 +static PyMethodDef LibcMethods[] = {
89 + {"tolower", _libc_tolower, METH_VARARGS, "Convert to lower case using system locale."},
90 + {"toupper", _libc_toupper, METH_VARARGS, "Convert to upper case using system locale."},
91 + {NULL, NULL, 0, NULL}
92 +};
93 +
94 +#if PY_MAJOR_VERSION >= 3
95 +static struct PyModuleDef moduledef = {
96 + PyModuleDef_HEAD_INIT,
97 + "libc", /* m_name */
98 + "Module for converting case using the system locale", /* m_doc */
99 + -1, /* m_size */
100 + LibcMethods, /* m_methods */
101 + NULL, /* m_reload */
102 + NULL, /* m_traverse */
103 + NULL, /* m_clear */
104 + NULL, /* m_free */
105 +};
106 +
107 +PyMODINIT_FUNC
108 +PyInit_libc(void)
109 +{
110 + PyObject *m;
111 + m = PyModule_Create(&moduledef);
112 + return m;
113 +}
114 +#else
115 +PyMODINIT_FUNC
116 +initlibc(void)
117 +{
118 + Py_InitModule("libc", LibcMethods);
119 +}
120 +#endif
121 +
122 +
123 +static PyObject *
124 +_libc_tolower(PyObject *self, PyObject *args)
125 +{
126 + int c;
127 +
128 + if (!PyArg_ParseTuple(args, "i", &c))
129 + return NULL;
130 +
131 + return Py_BuildValue("i", tolower(c));
132 +}
133 +
134 +
135 +static PyObject *
136 +_libc_toupper(PyObject *self, PyObject *args)
137 +{
138 + int c;
139 +
140 + if (!PyArg_ParseTuple(args, "i", &c))
141 + return NULL;
142 +
143 + return Py_BuildValue("i", toupper(c));
144 +}
145 --
146 2.7.3