Output a warning if LC_CTYPE is set to a value that causes libc
toupper() and/or tolower() conversions not apply correctly to printable
ASCII characters.
---
 pym/_emerge/actions.py     |  3 +++
 pym/portage/util/locale.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)
 create mode 100644 pym/portage/util/locale.py

diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
index 7f1cb59..e03e8d4 100644
--- a/pym/_emerge/actions.py
+++ b/pym/_emerge/actions.py
@@ -27,6 +27,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
        'portage.debug',
        'portage.news:count_unread_news,display_news_notifications',
        'portage.util._get_vm_info:get_vm_info',
+       'portage.util.locale:check_locale',
        'portage.emaint.modules.sync.sync:SyncRepos',
        '_emerge.chk_updated_cfg_files:chk_updated_cfg_files',
        '_emerge.help:help@emerge_help',
@@ -2467,6 +2468,8 @@ def validate_ebuild_environment(trees):
                for line in textwrap.wrap(msg, 65):
                        out.ewarn(line)
 
+       check_locale()
+
 def check_procfs():
        procfs_path = '/proc'
        if platform.system() not in ("Linux",) or \
diff --git a/pym/portage/util/locale.py b/pym/portage/util/locale.py
new file mode 100644
index 0000000..6919ceb
--- /dev/null
+++ b/pym/portage/util/locale.py
@@ -0,0 +1,63 @@
+#-*- coding:utf-8 -*-
+# Copyright 2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+"""
+Function to check whether the current used LC_CTYPE handles case
+transformations of ASCII characters in a way compatible with the POSIX
+locale.
+get_ro_checker().
+"""
+from __future__ import unicode_literals
+
+import logging
+import textwrap
+
+from portage.util import writemsg_level
+from portage.util._ctypes import find_library, LoadLibrary
+
+
+def check_locale():
+       """
+       Check whether the locale is sane. Returns True if it is, prints
+       warning and returns False if it is not. Returns None if the check
+       can not be executed due to platform limitations.
+       """
+
+       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))
+       rlc = [libc.tolower(c) for c in uc]
+       ruc = [libc.toupper(c) for c in lc]
+
+       if lc != rlc or uc != ruc:
+               msg = ("WARNING: The LC_CTYPE variable is set to a locale " +
+                       "that specifies transformation between lowercase " +
+                       "and uppercase ASCII characters that is different than 
" +
+                       "the one specified by POSIX locale. This can break " +
+                       "ebuilds and cause issues in programs that rely on " +
+                       "the common character conversion scheme. " +
+                       "Please consider enabling another locale (such as " +
+                       "en_US.UTF-8) in /etc/locale.gen and setting it " +
+                       "as LC_CTYPE in make.conf.")
+               msg = [l for l in textwrap.wrap(msg, 70)]
+               msg.append("")
+               chars = lambda l: ''.join(chr(x) for x in l)
+               if uc != ruc:
+                       msg.extend([
+                               "  %s -> %s" % (chars(lc), chars(ruc)),
+                               "  %28s: %s" % ('expected', chars(uc))])
+               if lc != rlc:
+                       msg.extend([
+                               "  %s -> %s" % (chars(uc), chars(rlc)),
+                               "  %28s: %s" % ('expected', chars(lc))])
+               writemsg_level("".join(["!!! %s\n" % l for l in msg]),
+                       level=logging.ERROR, noiselevel=-1)
+               return False
+
+       return True
-- 
2.6.3


Reply via email to