1 |
On 5/29/16 2:30 AM, Michał Górny wrote: |
2 |
> On Fri, 27 May 2016 10:26:44 -0400 |
3 |
> "Anthony G. Basile" <basile@××××××××××××××.edu> wrote: |
4 |
> |
5 |
>> From: "Anthony G. Basile" <blueness@g.o> |
6 |
>> |
7 |
>> The current method to check for a sane system locale is to use python's |
8 |
>> ctypes.util.find_library() to construct a full library path to the |
9 |
>> system libc.so and pass that path to ctypes.CDLL() so we can call |
10 |
>> toupper() and tolower() directly. However, this gets bogged down in |
11 |
>> implementation details and fails with musl. |
12 |
>> |
13 |
>> We work around this design flaw in ctypes with a small python module |
14 |
>> written in C which provides thin wrappers to toupper() and tolower(), |
15 |
>> and only fall back on the current ctypes-based check when this module |
16 |
>> is not available. |
17 |
>> |
18 |
>> This has been tested on glibc, uClibc and musl systems. |
19 |
>> |
20 |
>> X-Gentoo-bug: 571444 |
21 |
>> X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=571444 |
22 |
>> |
23 |
>> Signed-off-by: Anthony G. Basile <blueness@g.o> |
24 |
>> --- |
25 |
>> pym/portage/util/locale.py | 16 ++++++----- |
26 |
>> setup.py | 6 +++- |
27 |
>> src/portage_util_libc.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ |
28 |
>> 3 files changed, 84 insertions(+), 8 deletions(-) |
29 |
>> create mode 100644 src/portage_util_libc.c |
30 |
>> |
31 |
>> diff --git a/pym/portage/util/locale.py b/pym/portage/util/locale.py |
32 |
>> index 093eb86..5b09945 100644 |
33 |
>> --- a/pym/portage/util/locale.py |
34 |
>> +++ b/pym/portage/util/locale.py |
35 |
>> @@ -34,13 +34,15 @@ def _check_locale(silent): |
36 |
>> """ |
37 |
>> The inner locale check function. |
38 |
>> """ |
39 |
>> - |
40 |
>> - libc_fn = find_library("c") |
41 |
>> - if libc_fn is None: |
42 |
>> - return None |
43 |
>> - libc = LoadLibrary(libc_fn) |
44 |
>> - if libc is None: |
45 |
>> - return None |
46 |
>> + try: |
47 |
>> + from portage.util import libc |
48 |
>> + except ImportError: |
49 |
>> + libc_fn = find_library("c") |
50 |
>> + if libc_fn is None: |
51 |
>> + return None |
52 |
>> + libc = LoadLibrary(libc_fn) |
53 |
>> + if libc is None: |
54 |
>> + return None |
55 |
>> |
56 |
>> lc = list(range(ord('a'), ord('z')+1)) |
57 |
>> uc = list(range(ord('A'), ord('Z')+1)) |
58 |
>> diff --git a/setup.py b/setup.py |
59 |
>> index 25429bc..5ca8156 100755 |
60 |
>> --- a/setup.py |
61 |
>> +++ b/setup.py |
62 |
>> @@ -47,7 +47,11 @@ x_scripts = { |
63 |
>> # Dictionary custom modules written in C/C++ here. The structure is |
64 |
>> # key = module name |
65 |
>> # value = list of C/C++ source code, path relative to top source directory |
66 |
>> -x_c_helpers = {} |
67 |
>> +x_c_helpers = { |
68 |
>> + 'portage.util.libc' : [ |
69 |
>> + 'src/portage_util_libc.c', |
70 |
>> + ], |
71 |
>> +} |
72 |
>> |
73 |
>> class x_build(build): |
74 |
>> """ Build command with extra build_man call. """ |
75 |
>> diff --git a/src/portage_util_libc.c b/src/portage_util_libc.c |
76 |
>> new file mode 100644 |
77 |
>> index 0000000..00b09c2 |
78 |
>> --- /dev/null |
79 |
>> +++ b/src/portage_util_libc.c |
80 |
>> @@ -0,0 +1,70 @@ |
81 |
>> +/* Copyright 2005-2016 Gentoo Foundation |
82 |
>> + * Distributed under the terms of the GNU General Public License v2 |
83 |
>> + */ |
84 |
>> + |
85 |
>> +#include <Python.h> |
86 |
>> +#include <stdlib.h> |
87 |
>> +#include <ctype.h> |
88 |
>> + |
89 |
>> +static PyObject * _libc_tolower(PyObject *, PyObject *); |
90 |
>> +static PyObject * _libc_toupper(PyObject *, PyObject *); |
91 |
>> + |
92 |
>> +static PyMethodDef LibcMethods[] = { |
93 |
>> + {"tolower", _libc_tolower, METH_VARARGS, "Convert to lower case using system locale."}, |
94 |
>> + {"toupper", _libc_toupper, METH_VARARGS, "Convert to upper case using system locale."}, |
95 |
>> + {NULL, NULL, 0, NULL} |
96 |
>> +}; |
97 |
>> + |
98 |
>> +#if PY_MAJOR_VERSION >= 3 |
99 |
>> +static struct PyModuleDef moduledef = { |
100 |
>> + PyModuleDef_HEAD_INIT, |
101 |
>> + "libc", /* m_name */ |
102 |
>> + "Module for converting case using the system locale", /* m_doc */ |
103 |
>> + -1, /* m_size */ |
104 |
>> + LibcMethods, /* m_methods */ |
105 |
>> + NULL, /* m_reload */ |
106 |
>> + NULL, /* m_traverse */ |
107 |
>> + NULL, /* m_clear */ |
108 |
>> + NULL, /* m_free */ |
109 |
>> +}; |
110 |
>> +#endif |
111 |
>> + |
112 |
>> +PyMODINIT_FUNC |
113 |
> |
114 |
> Now you could call it nitpicking but since it decorates the function, |
115 |
> it would be better to have it inside the #ifdef. Otherwise, people |
116 |
> would think it's separate from that. |
117 |
|
118 |
You mean repeat it twice? |
119 |
|
120 |
> |
121 |
>> + |
122 |
>> +#if PY_MAJOR_VERSION >= 3 |
123 |
>> +PyInit_libc(void) |
124 |
>> +{ |
125 |
>> + PyObject *m; |
126 |
>> + m = PyModule_Create(&moduledef); |
127 |
>> + return m; |
128 |
>> +} |
129 |
>> +#else |
130 |
>> +initlibc(void) |
131 |
>> +{ |
132 |
>> + Py_InitModule("libc", LibcMethods); |
133 |
>> +} |
134 |
>> +#endif |
135 |
>> + |
136 |
>> + |
137 |
>> +static PyObject * |
138 |
>> +_libc_tolower(PyObject *self, PyObject *args) |
139 |
>> +{ |
140 |
>> + int c; |
141 |
>> + |
142 |
>> + if (!PyArg_ParseTuple(args, "i", &c)) |
143 |
>> + return NULL; |
144 |
>> + |
145 |
>> + return Py_BuildValue("i", tolower(c)); |
146 |
>> +} |
147 |
>> + |
148 |
>> + |
149 |
>> +static PyObject * |
150 |
>> +_libc_toupper(PyObject *self, PyObject *args) |
151 |
>> +{ |
152 |
>> + int c; |
153 |
>> + |
154 |
>> + if (!PyArg_ParseTuple(args, "i", &c)) |
155 |
>> + return NULL; |
156 |
>> + |
157 |
>> + return Py_BuildValue("i", toupper(c)); |
158 |
>> +} |
159 |
> |
160 |
> Aside from that, it look nice and shiny now. Thanks a lot! |
161 |
|
162 |
so what's the other stuff that could get put into this module that you |
163 |
mentioned? |
164 |
|
165 |
> |
166 |
|
167 |
|
168 |
-- |
169 |
Anthony G. Basile, Ph. D. |
170 |
Chair of Information Technology |
171 |
D'Youville College |
172 |
Buffalo, NY 14201 |
173 |
(716) 829-8197 |