[tor-commits] [arm/release] Support for rendering unicode characters if able

atagar at torproject.org atagar at torproject.org
Sun Jul 17 06:08:20 UTC 2011


commit f27c4c97a2abd0d89a235969ecee8ce77148ad9b
Author: Damian Johnson <atagar at torproject.org>
Date:   Fri May 20 19:52:11 2011 -0700

    Support for rendering unicode characters if able
    
    Checks for the multi-byte rendering type and curses wide character support,
    providing a util for checking if unicode rendering will work and enabling it
    if so.
---
 armrc.sample          |    3 ++
 src/cli/controller.py |    8 +++++-
 src/util/uiTools.py   |   71 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+), 1 deletions(-)

diff --git a/armrc.sample b/armrc.sample
index 9f75ccc..ecfe45a 100644
--- a/armrc.sample
+++ b/armrc.sample
@@ -19,6 +19,9 @@ queries.useProc true
 # Renders the interface with color if set and the terminal supports it
 features.colorInterface true
 
+# Includes unicode characters in the interface.
+features.printUnicode true
+
 # Checks the torrc for issues, warning and hilighting problems if true
 features.torrc.validate true
 
diff --git a/src/cli/controller.py b/src/cli/controller.py
index a1ec58a..8222da8 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -4,6 +4,7 @@ user input to the proper panels.
 """
 
 import time
+import locale
 import curses
 import threading
 
@@ -18,7 +19,7 @@ import cli.graphing.connStats
 import cli.graphing.resourceStats
 import cli.connections.connPanel
 
-from util import connections, conf, enum, log, panel, sysTools, torConfig, torTools
+from util import connections, conf, enum, log, panel, sysTools, torConfig, torTools, uiTools
 
 ARM_CONTROLLER = None
 
@@ -459,6 +460,11 @@ def drawTorMonitor(stdscr, startTime):
   try: curses.curs_set(0)
   except curses.error: pass
   
+  # If using our LANG variable for rendering multi-byte characters lets us
+  # get unicode support then then use it.
+  if uiTools.isUnicodeAvailable():
+    locale.setlocale(locale.LC_ALL, "")
+  
   # logs the initialization time
   msg = "arm started (initialization took %0.3f seconds)" % (time.time() - startTime)
   log.log(CONFIG["log.startTime"], msg)
diff --git a/src/util/uiTools.py b/src/util/uiTools.py
index b3b919a..0ff680e 100644
--- a/src/util/uiTools.py
+++ b/src/util/uiTools.py
@@ -5,6 +5,7 @@ easy method of providing the following interface components:
 - unit conversion for labels
 """
 
+import os
 import sys
 import curses
 
@@ -35,8 +36,13 @@ TIME_UNITS = [(86400.0, "d", " day"), (3600.0, "h", " hour"),
 Ending = enum.Enum("ELLIPSE", "HYPHEN")
 SCROLL_KEYS = (curses.KEY_UP, curses.KEY_DOWN, curses.KEY_PPAGE, curses.KEY_NPAGE, curses.KEY_HOME, curses.KEY_END)
 CONFIG = {"features.colorInterface": True,
+          "features.printUnicode": True,
           "log.cursesColorSupport": log.INFO}
 
+# Flag indicating if unicode is supported by curses. If None then this has yet
+# to be determined.
+IS_UNICODE_SUPPORTED = None
+
 def loadConfig(config):
   config.update(CONFIG)
 
@@ -87,6 +93,29 @@ def _showGlyphs(stdscr):
   
   stdscr.getch() # quit on keyboard input
 
+def isUnicodeAvailable():
+  """
+  True if curses has wide character support, false otherwise or if it can't be
+  determined.
+  """
+  
+  global IS_UNICODE_SUPPORTED
+  if IS_UNICODE_SUPPORTED == None:
+    import sysTools
+    
+    if CONFIG["features.printUnicode"]:
+      # Checks if our LANG variable is unicode. This is what will be respected
+      # when printing multi-byte characters after calling...
+      # locale.setlocale(locale.LC_ALL, '')
+      # 
+      # so if the LANG isn't unicode then setting this would be pointless.
+      
+      isLangUnicode = "utf-" in os.environ.get("LANG", "").lower()
+      IS_UNICODE_SUPPORTED = isLangUnicode and _isWideCharactersAvailable()
+    else: IS_UNICODE_SUPPORTED = False
+  
+  return IS_UNICODE_SUPPORTED
+
 def getPrintable(line, keepNewlines = True):
   """
   Provides the line back with non-printable characters stripped.
@@ -606,6 +635,48 @@ def _getLabel(units, count, decimal, isLong):
         return countLabel + longLabel + ("s" if isPlural else "")
       else: return countLabel + shortLabel
 
+def _isWideCharactersAvailable():
+  """
+  True if curses has wide character support (which is required to print
+  unicode). False otherwise.
+  """
+  
+  try:
+    # gets the dynamic library used by the interpretor for curses
+    
+    import _curses
+    cursesLib = _curses.__file__
+    
+    # Uses 'ldd' (Linux) or 'otool -L' (Mac) to determine the curses
+    # library dependencies.
+    # 
+    # atagar at fenrir:~/Desktop$ ldd /usr/lib/python2.6/lib-dynload/_curses.so
+    #   linux-gate.so.1 =>  (0x00a51000)
+    #   libncursesw.so.5 => /lib/libncursesw.so.5 (0x00faa000)
+    #   libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0x002f1000)
+    #   libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00158000)
+    #   libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0x00398000)
+    #   /lib/ld-linux.so.2 (0x00ca8000)
+    # 
+    # atagar$ otool -L /System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-dynload/_curses.so
+    # /System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-dynload/_curses.so:
+    #   /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
+    #   /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
+    #   /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.6)
+    
+    libDependencyLines = None
+    if sysTools.isAvailable("ldd"):
+      libDependencyLines = sysTools.call("ldd %s" % cursesLib)
+    elif sysTools.isAvailable("otool"):
+      libDependencyLines = sysTools.call("otool -L %s" % cursesLib)
+    
+    if libDependencyLines:
+      for line in libDependencyLines:
+        if "libncursesw" in line: return True
+  except: pass
+  
+  return False
+
 def _initColors():
   """
   Initializes color mappings usable by curses. This can only be done after





More information about the tor-commits mailing list