From: Dmitry Bogatov <KAction@debian.org>
Date: Fri, 30 Aug 2019 20:34:11 +0000
Subject: Make fbless work with Python3

Closes: #936506
---
 fbless                    |  4 ++--
 fbless_lib/fb2parser.py   | 16 ++++++-------
 fbless_lib/hyphenation.py | 31 ++++++++++++-------------
 fbless_lib/main.py        | 40 ++++++++++++++++----------------
 fbless_lib/options.py     | 10 ++++----
 fbless_lib/paragraph.py   | 58 +++++++++++++++++++++++------------------------
 6 files changed, 79 insertions(+), 80 deletions(-)

diff --git a/fbless b/fbless
index 223dee6..48bec26 100755
--- a/fbless
+++ b/fbless
@@ -5,7 +5,7 @@
 
 import sys
 import locale
-from cStringIO import StringIO
+from io import StringIO
 import curses
 from fbless_lib.options import parse_arguments
 from fbless_lib.main import MainWindow
@@ -29,7 +29,7 @@ finally:
 
 value = sys.stdout.getvalue()
 if value:
-    print >> stdout, value
+    print(value, file=stdout)
 
 ## value = sys.stderr.getvalue()
 ## if value:
diff --git a/fbless_lib/fb2parser.py b/fbless_lib/fb2parser.py
index eb8b02b..aec9015 100644
--- a/fbless_lib/fb2parser.py
+++ b/fbless_lib/fb2parser.py
@@ -2,11 +2,11 @@
 
 import sys
 import string
-from cStringIO import StringIO
+from io import StringIO
 import xml.sax
 import xml.parsers.expat
 
-from paragraph import Paragraph, attr
+from .paragraph import Paragraph, attr
 
 
 class StopParsing(Exception):
@@ -51,7 +51,7 @@ class ContentHandler:
         elif name == 'stanza':
             self.add_empty_line()
         elif name == 'image':
-            for atr in attrs.keys():
+            for atr in list(attrs.keys()):
                 if atr.endswith('href'):
                     self.add_empty_line()
                     self.cur_data = '[' + attrs[atr][1:] + ']'
@@ -62,7 +62,7 @@ class ContentHandler:
             self.cur_attr = [sum(map(len, self.cur_data)), attr[name]]
         elif name == 'a':
             href = None
-            for atr in attrs.keys():
+            for atr in list(attrs.keys()):
                 if atr.endswith('href'):
                     href = attrs[atr]
                     break
@@ -162,15 +162,15 @@ class ContentHandler:
 
 def fb2parse(data):
 
-    if not data.startswith('<?xml'):
-        print 'Warning: file is not an XML file. Skipped.'
+    if not data.startswith(b'<?xml'):
+        print('Warning: file is not an XML file. Skipped.')
         return None
 
     global _parser
 
     # remove invalid chars
-    tab = string.maketrans('', '')
-    data = data.translate(tab, '\07\032')  # XXX: add other invalid chars here
+    data = data.replace(b'\07', b'')
+    data = data.replace(b'\032', b'')
 
     content_handler = ContentHandler()
 
diff --git a/fbless_lib/hyphenation.py b/fbless_lib/hyphenation.py
index fc59a62..4cd748a 100644
--- a/fbless_lib/hyphenation.py
+++ b/fbless_lib/hyphenation.py
@@ -12,9 +12,9 @@ else:
     dict_files_dir = os.path.join('fbless_lib', 'hyph_dicts')
 ru_dict_file = os.path.join(dict_files_dir, 'hyph_ru.dic')
 
-vowels = unicode('аеёиоуыэюяАЕЁИОУЫЭЮЯ', 'utf8')
-consonants = unicode('бвгджзйклмнпрстфхцчшщБВГДЖЗЙКЛМНПРСТФХЦЧШЩ', 'utf8')
-hardsoftsigns = unicode('ъьЪЬ', 'utf8')
+vowels = str('аеёиоуыэюяАЕЁИОУЫЭЮЯ')
+consonants = str('бвгджзйклмнпрстфхцчшщБВГДЖЗЙКЛМНПРСТФХЦЧШЩ')
+hardsoftsigns = str('ъьЪЬ')
 
 class Hyphenation:
 
@@ -34,7 +34,7 @@ class Hyphenation:
         self.dict_files_dir = dfd
 
         if not dfd:
-            print 'ERROR: can\'t read hyphenation files'
+            print('ERROR: can\'t read hyphenation files')
             return
 
         self.langs = []
@@ -46,8 +46,7 @@ class Hyphenation:
         if self.langs:
             return self.langs
 
-        langs = map(lambda x: x[len(self.dict_files_dir)+6:-4],
-                    glob(os.path.join(self.dict_files_dir, 'hyph_*.dic')))
+        langs = [x[len(self.dict_files_dir)+6:-4] for x in glob(os.path.join(self.dict_files_dir, 'hyph_*.dic'))]
         if os.path.exists(os.path.join(self.dict_files_dir, 'langs.txt')):
             for s in open(os.path.join(self.dict_files_dir, 'langs.txt')).readlines():
                 s1, s2 = s.split(' ', 1)
@@ -75,7 +74,7 @@ class Hyphenation:
         encoding = fd.readline().strip()
 
         for l in fd.readlines():
-            l = unicode(l, encoding).strip()
+            l = str(l, encoding).strip()
 
             ii = []
             i = 0
@@ -109,8 +108,8 @@ class Hyphenation:
             hyphenate_func = self.tex_hyphenate
 
         words_list = []
-        w = u''
-        ww = u''
+        w = ''
+        ww = ''
 
         # split words
         for i in word:
@@ -123,7 +122,7 @@ class Hyphenation:
                 if i == '-':
                     words_list.append(w+ww)
                 w += ww+i
-                ww = u''
+                ww = ''
 
         if ww:
             for j in hyphenate_func(ww, lang):
@@ -166,19 +165,19 @@ class Hyphenation:
 
     def tex_hyphenate(self, word, lang='ru'):
 
-        if not self.hyph_pats.has_key(lang):
+        if lang not in self.hyph_pats:
             self.hyph_pats[lang] = self.read_patterns(lang)
         if not self.hyph_pats[lang]:
             return []
 
         hyph_pats = self.hyph_pats[lang]
 
-        w = u'.'+word.lower()+u'.'
+        w = '.'+word.lower()+'.'
         h_list = [0]*len(w)
 
         for a in range(len(w)+1):
             for b in range(a):
-                if hyph_pats.has_key(w[b:a]):
+                if w[b:a] in hyph_pats:
                     h = hyph_pats[w[b:a]]
                     #print '>>', w[b:a].encode('utf-8'), h
                     for i, j in h:
@@ -210,12 +209,12 @@ if __name__ == '__main__':
     ## Russian
     for w in ('стэнфорд',):
         i = 0
-        hl = h.hyphenate(unicode(w), 'ru-tex')
+        hl = h.hyphenate(str(w), 'ru-tex')
         hl.reverse()
         for l in hl:
-            print l[i:].encode('utf-8'),
+            print(l[i:].encode('utf-8'), end=' ')
             i = len(l)
-        print w[i:]
+        print(w[i:])
 ##     for w in ('пере-Стройка','безусловный','полу-остров','автоматизация',
 ##               'спецотдел','специалист'):
 ##         i = 0
diff --git a/fbless_lib/main.py b/fbless_lib/main.py
index 1e1340e..d67a01e 100644
--- a/fbless_lib/main.py
+++ b/fbless_lib/main.py
@@ -8,16 +8,16 @@ import traceback
 import locale
 import signal
 import zipfile
-from cStringIO import StringIO
+from io import StringIO
 import time
 import curses
 import curses.ascii as ascii
 
-from fb2parser import fb2parse
-from paragraph import attr
-import options
-import const
-from options import convert_color, get_keys
+from .fb2parser import fb2parse
+from .paragraph import attr
+from . import options
+from . import const
+from .options import convert_color, get_keys
 
 default_charset = locale.getdefaultlocale()[1]
 
@@ -127,7 +127,7 @@ class MainWindow:
             os.makedirs(os.path.dirname(save_file))
         fd = open(save_file, 'w')
         for l in save_pos:
-            print >> fd, ' '.join(l)
+            print(' '.join(l), file=fd)
 
     def init_color(self):
         n = 1
@@ -341,7 +341,7 @@ class MainWindow:
             # counting from the left hand side is a number of 
             # bytes in a utf8 multi-char.
             byte_count = 0
-            for i in xrange (8):
+            for i in range (8):
                 if not bool (c & (1 << (7 - i))):
                     byte_count = i;
                     break;
@@ -354,7 +354,7 @@ class MainWindow:
 
             c = [c]
             if byte_count >= 2:
-                for i in xrange (byte_count - 1):
+                for i in range (byte_count - 1):
                     c.append (self.screen.getch ())
             
             # Create a string from the list of bytes.
@@ -406,7 +406,7 @@ class MainWindow:
 
         # Ignore the errors happening when deleting the
         # multi-byte characters.
-        s = unicode(s, default_charset, errors='ignore')
+        s = str(s, default_charset, errors='ignore')
         self.screen.nodelay(1)
         
         if not s:
@@ -451,7 +451,7 @@ class MainWindow:
 
         # Ignore the errors happening when deleting the
         # multi-byte characters.
-        s = unicode(s, default_charset, errors='ignore')
+        s = str(s, default_charset, errors='ignore')
         s = s.encode(default_charset)
         self.update_status = True
         try:
@@ -475,7 +475,7 @@ class MainWindow:
             if id.startswith('#'):
                 id = id[1:]
             else:
-                print 'external link:', id
+                print('external link:', id)
                 return
             i = self.content.get_by_id(id)
             if i is None:
@@ -1070,16 +1070,16 @@ def create_content(filename, scr_cols):
         zf = zipfile.ZipFile(filename)
         for zip_filename in zf.namelist():
             data = zf.read(zip_filename)
-            if data.startswith('<?xml'):
+            if data.startswith(b'<?xml'):
                 break
         else:
             sys.exit('zip archive: xml file not found')
     else:
-        data = open(filename).read()
-        if data.startswith('BZh'):
+        data = open(filename, 'rb').read()
+        if data.startswith(b'BZh'):
             import bz2
             data = bz2.decompress(data)
-        elif data.startswith('\x1f\x8b'):
+        elif data.startswith(b'\x1f\x8b'):
             import gzip
             data = gzip.GzipFile(fileobj=StringIO(data)).read()
     content = fb2parse(data)
@@ -1096,16 +1096,16 @@ if __name__ == '__main__':
             s, t = c.get(pi, li)
         except IndexError:
             break
-        print t, '>' + s + '<'
+        print(t, '>' + s + '<')
         pi, li = c.indexes()
         li += 1
         i += 1
         if i > 200:
             break
-    print '---------->', pi, li
+    print('---------->', pi, li)
     s, t = c.get(pi, li - 32)
-    print s
-    print c.indexes()
+    print(s)
+    print(c.indexes())
     #while True:
     #    s, t = c.get(pi, li)
 ##     try:
diff --git a/fbless_lib/options.py b/fbless_lib/options.py
index d4e6b07..4f0620e 100644
--- a/fbless_lib/options.py
+++ b/fbless_lib/options.py
@@ -2,10 +2,10 @@
 """ Default options dicts and config files parser
 """
 import curses
-import ConfigParser
+import configparser
 import os
-import defaults
-import const 
+from . import defaults
+from . import const 
 import sys
 import argparse
 
@@ -75,7 +75,7 @@ def convert_color(colorname):
             return(colorname)
 
 def parse_arguments():
-    parser = argparse.ArgumentParser(description = 'fb2 console reader', version = const.VERSION)
+    parser = argparse.ArgumentParser(description = 'fb2 console reader')
     parser.add_argument('file', nargs = '?',
                         help = 'fb2, zip, gzip or bzip2 file')
     parser.add_argument('-a', '--autoscroll', action = 'store_true',
@@ -138,7 +138,7 @@ def parse_arguments():
 def parse_config():
     """Load settings from config
     """
-    config = ConfigParser.RawConfigParser()
+    config = configparser.RawConfigParser()
     config.read(CONFIG_FILES)
 
     for d, section in (
diff --git a/fbless_lib/paragraph.py b/fbless_lib/paragraph.py
index c7461bd..137bf0a 100644
--- a/fbless_lib/paragraph.py
+++ b/fbless_lib/paragraph.py
@@ -3,8 +3,8 @@
 import sys
 import locale
 
-from hyphenation import Hyphenation
-from options import styles, general
+from .hyphenation import Hyphenation
+from .options import styles, general
 
 default_charset = locale.getdefaultlocale()[1]
 hyph = Hyphenation()
@@ -12,34 +12,34 @@ hyph = Hyphenation()
 
 def replace(s):
     """ Здесь происходит замена символов, если требуется
-        u'\u2013' -> '--'
-        u'\u2014' -> '---'
+        u'\\u2013' -> '--'
+        u'\\u2014' -> '---'
         u'\xa0'   -> неразрывный пробел
-        u'\u2026' -> dots...
+        u'\\u2026' -> dots...
         u'\xab'   -> '<<'
         u'\xbb'   -> '>>'
-        u'\u201c' -> ``
-        u'\u201d' -> ''
-        u'\u201e' -> ,,
+        u'\\u201c' -> ``
+        u'\\u201d' -> ''
+        u'\\u201e' -> ,,
         u'\xad'   -> мягкий перенос
 
         Правда, параметры метода .replace(), почему-то иные стоят.
     """
     return (s
-        .replace(u'\u2013', u'-')
-        .replace(u'\u2014', u'-')
-        .replace(u'\xa0', u' ')
-        .replace(u'\u2026', u'...')
+        .replace('\u2013', '-')
+        .replace('\u2014', '-')
+        .replace('\xa0', ' ')
+        .replace('\u2026', '...')
         #.replace(u'\xab', u'<<')
         #.replace(u'\xbb', u'>>')
-        .replace(u'\xab', u'"')
-        .replace(u'\xbb', u'"')
-        .replace(u'\u201c', u'"')
-        .replace(u'\u201d', u'"')
-        .replace(u'\u201e', u'"')
-        .replace(u'\u2116', u'No')
-        .replace(u'\xad', '')
-        .replace(u'\u2019', '\'')
+        .replace('\xab', '"')
+        .replace('\xbb', '"')
+        .replace('\u201c', '"')
+        .replace('\u201d', '"')
+        .replace('\u201e', '"')
+        .replace('\u2116', 'No')
+        .replace('\xad', '')
+        .replace('\u2019', '\'')
     )
 
 
@@ -239,14 +239,14 @@ class Paragraph:
                 len_line = sum(len(s) for s in ln
                                if not isinstance(s, (int, tuple)))
                 d = (max_len - len_line) / 2
-                spaces = ' ' * (self.left_indent + d)
+                spaces = ' ' * int(self.left_indent + d)
             elif self.justify == 'right':
                 len_line = sum(len(s) for s in ln
                                if not isinstance(s, (int, tuple)))
                 d = max_len - len_line
-                spaces = ' ' * (self.left_indent + d)
+                spaces = ' ' * int(self.left_indent + d)
             else:  # left or fill
-                spaces = ' ' * self.left_indent
+                spaces = ' ' * int(self.left_indent)
 
             if general['center_text']:
                 # to center text, we pad it with spaces from the left
@@ -263,7 +263,7 @@ class Paragraph:
 
 
 if __name__ == '__main__':
-    s = unicode(
+    s = str(
         'Давно было готово заглавие, использующее титул замечательной '
         'монографии :вана Аксенова "Пикассо и окрестности". Предрешен '
         'был и тот свободный жанр "филологического романа", в котором '
@@ -280,13 +280,13 @@ if __name__ == '__main__':
     par.split_string()
     for l in par.lines:
         if 0:
-            print l
+            print(l)
         elif 0:
             for w in l:
                 if w == ' ':
-                    print '<sp>'
+                    print('<sp>')
                 else:
-                    print w
+                    print(w)
         else:
             for w in l:
                 if isinstance(w, int):
@@ -298,8 +298,8 @@ if __name__ == '__main__':
                     #print w,
                     #sys.stdout.write('|')
                     sys.stdout.write(w.encode('utf-8', 'replace'))
-            print
-    print '~' * (par.scr_cols - par.right_indent)
+            print()
+    print('~' * (par.scr_cols - par.right_indent))
 
     #par.print_str()
 ##     for s in par.lines:
