]> git.lyx.org Git - lyx.git/blobdiff - lib/configure.py
ANNOUNCE updates.
[lyx.git] / lib / configure.py
index 4ba71c953f7b3c8732068714620e848d1e5d9571..f0efb0fe668d1cccbee5ccbcc9251730ad41777f 100644 (file)
@@ -25,6 +25,13 @@ console.setFormatter(formatter)
 logger = logging.getLogger('LyX')
 logger.addHandler(console)
 
+def quoteIfSpace(name):
+    " utility function: quote name if it contains spaces "
+    if ' ' in name:
+        return '"' + name + '"'
+    else:
+        return name
+
 def writeToFile(filename, lines, append = False):
     " utility function: write or append lines to filename "
     if append:
@@ -57,10 +64,10 @@ def removeFiles(filenames):
             pass
 
 
-def cmdOutput(cmd, async = False):
+def cmdOutput(cmd, asynchronous = False):
     '''utility function: run a command and get its output as a string
         cmd: command to run
-        async: if False, return whole output as a string, otherwise
+        asynchronous: if False, return whole output as a string, otherwise
                return the stdout handle from which the output can be
                read (the caller is then responsible for closing it)
     '''
@@ -72,10 +79,10 @@ def cmdOutput(cmd, async = False):
             cmd = 'cmd /d /c pushd ' + shortPath(os.getcwd()) + '&' + cmd
     else:
         b = True
-    pipe = subprocess.Popen(cmd, shell=b, close_fds=b, stdin=subprocess.PIPE, \
+    pipe = subprocess.Popen(cmd, shell=b, close_fds=b, stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, universal_newlines=True)
     pipe.stdin.close()
-    if async:
+    if asynchronous:
         return pipe.stdout
     output = pipe.stdout.read()
     pipe.stdout.close()
@@ -110,16 +117,16 @@ def setEnviron():
 
 def copy_tree(src, dst, preserve_symlinks=False, level=0):
     ''' Copy an entire directory tree 'src' to a new location 'dst'.
+
     Code inspired from distutils.copy_tree.
-        Copying ignores non-regular files and the cache directory.
+         Copying ignores non-regular files and the cache directory.
     Pipes may be present as leftovers from LyX for lyx-server.
 
     If 'preserve_symlinks' is true, symlinks will be
     copied as symlinks (on platforms that support them!); otherwise
     (the default), the destination of the symlink will be copied.
     '''
+
     if not os.path.isdir(src):
         raise FileError("cannot copy tree '%s': not a directory" % src)
     try:
@@ -127,12 +134,12 @@ def copy_tree(src, dst, preserve_symlinks=False, level=0):
     except os.error as oserror:
         (errno, errstr) = oserror.args
         raise FileError("error listing files in '%s': %s" % (src, errstr))
+
     if not os.path.isdir(dst):
         os.makedirs(dst)
+
     outputs = []
+
     for name in names:
         src_name = os.path.join(src, name)
         dst_name = os.path.join(dst, name)
@@ -150,7 +157,7 @@ def copy_tree(src, dst, preserve_symlinks=False, level=0):
             outputs.append(dst_name)
         else:
             logger.info("Ignore non-regular file %s", src_name)
+
     return outputs
 
 
@@ -163,20 +170,20 @@ def checkUpgrade():
         logger.info('Checking for upgrade from previous version.')
         parent = os.path.dirname(cwd)
         appname = basename[:(-len(version_suffix))]
-        for version in ['-2.1', '-2.0', '-1.6' ]:
+        for version in ['-2.2', '-2.1', '-2.0', '-1.6' ]:
             logger.debug('Checking for upgrade from previous version ' + version)
             previous = os.path.join(parent, appname + version)
             logger.debug('previous = ' + previous)
             if os.path.isdir( previous ):
                 logger.info('Found directory "%s".', previous)
                 copy_tree( previous, cwd, True )
-                logger.info('Content copied to directory "%s".', cwd)
+                logger.info('Content copied from directory "%s".', previous)
                 return
 
 
 def createDirectories():
     ''' Create the build directories if necessary '''
-    for dir in ['bind', 'clipart', 'doc', 'examples', 'images', 'kbd', \
+    for dir in ['bind', 'clipart', 'doc', 'examples', 'images', 'kbd',
         'layouts', 'scripts', 'templates', 'ui' ]:
         if not os.path.isdir( dir ):
             try:
@@ -196,23 +203,22 @@ def checkTeXPaths():
         from tempfile import mkstemp
         fd, tmpfname = mkstemp(suffix='.ltx')
         if os.name == 'nt':
-            from locale import getdefaultlocale
-            language, encoding = getdefaultlocale()
-            if encoding == None:
-                encoding = 'latin1'
+            encoding = sys.getfilesystemencoding()
             if sys.version_info[0] < 3:
                 inpname = shortPath(unicode(tmpfname, encoding)).replace('\\', '/')
             else:
-                inpname = shortPath(str(tmpfname, encoding)).replace('\\', '/')
+                inpname = shortPath(tmpfname).replace('\\', '/') 
         else:
             inpname = cmdOutput('cygpath -m ' + tmpfname)
         logname = os.path.basename(re.sub("(?i).ltx", ".log", inpname))
         inpname = inpname.replace('~', '\\string~')
-        os.write(fd, r'\relax')
+        os.write(fd, b'\\relax')
         os.close(fd)
-        latex_out = cmdOutput(r'latex "\nonstopmode\input{%s}\makeatletter\@@end"' % inpname)
+        latex_out = cmdOutput(r'latex "\nonstopmode\input{%s}\makeatletter\@@end"'
+                              % inpname)
         if 'Error' in latex_out:
-            latex_out = cmdOutput(r'latex "\nonstopmode\input{\"%s\"}\makeatletter\@@end"' % inpname)
+            latex_out = cmdOutput(r'latex "\nonstopmode\input{\"%s\"}\makeatletter\@@end"'
+                                  % inpname)
         if 'Error' in latex_out:
             logger.warning("configure: TeX engine needs posix-style paths in latex files")
             windows_style_tex_paths = 'false'
@@ -252,7 +258,8 @@ def checkProg(description, progs, rc_entry = [], path = [], not_found = ''):
     '''
     # one rc entry for each progs plus not_found entry
     if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
-        logger.error("rc entry should have one item or item for each prog and not_found.")
+        logger.error("rc entry should have one item or item "
+                     "for each prog and not_found.")
         sys.exit(2)
     logger.info('checking for ' + description + '...')
     ## print '(' + ','.join(progs) + ')',
@@ -262,10 +269,11 @@ def checkProg(description, progs, rc_entry = [], path = [], not_found = ''):
     if "PATHEXT" in os.environ:
         extlist = extlist + os.environ["PATHEXT"].split(os.pathsep)
     global java, perl
+    unquoted_space = re.compile(r'''((?:[^ "']|"[^"]*"|'[^']*')+)''')
     for idx in range(len(progs)):
         # ac_prog may have options, ac_word is the command name
-        ac_prog = progs[idx]
-        ac_word = ac_prog.split(' ')[0]
+        ac_prog = progs[idx].replace('"', '\\"')
+        ac_word = unquoted_space.split(progs[idx])[1::2][0].strip('"')
         if (ac_word.endswith('.class') or ac_word.endswith('.jar')) and java == '':
             continue
         if ac_word.endswith('.pl') and perl == '':
@@ -279,13 +287,17 @@ def checkProg(description, progs, rc_entry = [], path = [], not_found = ''):
                     logger.info(msg + ' yes')
                     # deal with java and perl
                     if ac_word.endswith('.class'):
-                        ac_prog = ac_prog.replace(ac_word, r'%s \"%s\"' % (java, os.path.join(ac_dir, ac_word[:-6])))
+                        ac_prog = ac_prog.replace(ac_word, r'%s \"%s\"'
+                                    % (java, os.path.join(ac_dir, ac_word[:-6])))
                     elif ac_word.endswith('.jar'):
-                        ac_prog = ac_prog.replace(ac_word, r'%s -jar \"%s\"' % (java, os.path.join(ac_dir, ac_word)))
+                        ac_prog = ac_prog.replace(ac_word, r'%s -jar \"%s\"'
+                                    % (java, os.path.join(ac_dir, ac_word)))
                     elif ac_word.endswith('.pl'):
-                        ac_prog = ac_prog.replace(ac_word, r'%s -w \"%s\"' % (perl, os.path.join(ac_dir, ac_word)))
+                        ac_prog = ac_prog.replace(ac_word, r'%s -w \"%s\"'
+                                    % (perl, os.path.join(ac_dir, ac_word)))
                     elif ac_dir in additional_path:
-                        ac_prog = ac_prog.replace(ac_word, r'\"%s\"' % (os.path.join(ac_dir, ac_word)))
+                        ac_prog = ac_prog.replace(ac_word, r'\"%s\"'
+                                    % (os.path.join(ac_dir, ac_word)))
                     # write rc entries for this command
                     if len(rc_entry) == 1:
                         addToRC(rc_entry[0].replace('%%', ac_prog))
@@ -300,7 +312,8 @@ def checkProg(description, progs, rc_entry = [], path = [], not_found = ''):
     return ['', not_found]
 
 
-def checkProgAlternatives(description, progs, rc_entry = [], alt_rc_entry = [], path = [], not_found = ''):
+def checkProgAlternatives(description, progs, rc_entry = [],
+                          alt_rc_entry = [], path = [], not_found = ''):
     '''
         The same as checkProg, but additionally, all found programs will be added
         as alt_rc_entries
@@ -340,13 +353,17 @@ def checkProgAlternatives(description, progs, rc_entry = [], alt_rc_entry = [],
                     m = None
                     # deal with java and perl
                     if ac_word.endswith('.class'):
-                        ac_prog = ac_prog.replace(ac_word, r'%s \"%s\"' % (java, os.path.join(ac_dir, ac_word[:-6])))
+                        ac_prog = ac_prog.replace(ac_word, r'%s \"%s\"'
+                                    % (java, os.path.join(ac_dir, ac_word[:-6])))
                     elif ac_word.endswith('.jar'):
-                        ac_prog = ac_prog.replace(ac_word, r'%s -jar \"%s\"' % (java, os.path.join(ac_dir, ac_word)))
+                        ac_prog = ac_prog.replace(ac_word, r'%s -jar \"%s\"'
+                                    % (java, os.path.join(ac_dir, ac_word)))
                     elif ac_word.endswith('.pl'):
-                        ac_prog = ac_prog.replace(ac_word, r'%s -w \"%s\"' % (perl, os.path.join(ac_dir, ac_word)))
+                        ac_prog = ac_prog.replace(ac_word, r'%s -w \"%s\"'
+                                    % (perl, os.path.join(ac_dir, ac_word)))
                     elif ac_dir in additional_path:
-                        ac_prog = ac_prog.replace(ac_word, r'\"%s\"' % (os.path.join(ac_dir, ac_word)))
+                        ac_prog = ac_prog.replace(ac_word, r'\"%s\"'
+                                    % (os.path.join(ac_dir, ac_word)))
                     # write rc entries for this command
                     if found_prime == False:
                         if len(rc_entry) == 1:
@@ -438,33 +455,38 @@ def listAlternatives(progs, alt_type, rc_entry = []):
 def checkViewer(description, progs, rc_entry = [], path = []):
     ''' The same as checkProgAlternatives, but for viewers '''
     alt_rc_entry = listAlternatives(progs, 'viewer', rc_entry)
-    return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
+    return checkProgAlternatives(description, progs, rc_entry,
+                                 alt_rc_entry, path, not_found = 'auto')
 
 
 def checkEditor(description, progs, rc_entry = [], path = []):
     ''' The same as checkProgAlternatives, but for editors '''
     alt_rc_entry = listAlternatives(progs, 'editor', rc_entry)
-    return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
+    return checkProgAlternatives(description, progs, rc_entry,
+                                 alt_rc_entry, path, not_found = 'auto')
 
 
 def checkViewerNoRC(description, progs, rc_entry = [], path = []):
     ''' The same as checkViewer, but do not add rc entry '''
     alt_rc_entry = listAlternatives(progs, 'viewer', rc_entry)
     rc_entry = []
-    return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
+    return checkProgAlternatives(description, progs, rc_entry,
+                                 alt_rc_entry, path, not_found = 'auto')
 
 
 def checkEditorNoRC(description, progs, rc_entry = [], path = []):
     ''' The same as checkViewer, but do not add rc entry '''
     alt_rc_entry = listAlternatives(progs, 'editor', rc_entry)
     rc_entry = []
-    return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
+    return checkProgAlternatives(description, progs, rc_entry,
+                                 alt_rc_entry, path, not_found = 'auto')
 
 
 def checkViewerEditor(description, progs, rc_entry = [], path = []):
     ''' The same as checkProgAlternatives, but for viewers and editors '''
     alt_rc_entry = listAlternatives(progs, ['editor', 'viewer'], rc_entry)
-    return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
+    return checkProgAlternatives(description, progs, rc_entry,
+                                 alt_rc_entry, path, not_found = 'auto')
 
 
 def checkDTLtools():
@@ -480,7 +502,16 @@ def checkDTLtools():
 
 def checkInkscape():
     ''' Check whether Inkscape is available and return the full path (Windows only) '''
-    if os.name != 'nt':
+    ''' On Mac OS (darwin) a wrapper is used - therefore the version is checked '''
+    ''' The answer of the real inkscape is validated and a fake binary used if this fails '''
+    if sys.platform == 'darwin':
+        version_string = cmdOutput("inkscape --version")
+        match = re.match('^Inkscape', version_string)
+        if match:
+            return 'inkscape'
+        else:
+            return 'inkscape-binary'
+    elif os.name != 'nt':
         return 'inkscape'
     if sys.version_info[0] < 3:
         import _winreg as winreg
@@ -490,12 +521,12 @@ def checkInkscape():
     try:
         aKey = winreg.OpenKey(aReg, r"inkscape.svg\DefaultIcon")
         val = winreg.QueryValueEx(aKey, "")
-        return str(val[0]).split('"')[1].replace('.exe', '')
+        return str(val[0]).split('"')[1]
     except EnvironmentError:
         try:
             aKey = winreg.OpenKey(aReg, r"Applications\inkscape.exe\shell\open\command")
             val = winreg.QueryValueEx(aKey, "")
-            return str(val[0]).split('"')[1].replace('.exe', '')
+            return str(val[0]).split('"')[1]
         except EnvironmentError:
             return 'inkscape'
 
@@ -589,7 +620,7 @@ def checkFormatEntries(dtl_tools):
     checkViewerEditor('a FEN viewer and editor', ['xboard -lpf $$i -mode EditPosition'],
         rc_entry = [r'\Format fen        fen     FEN                    "" "%%"        "%%"    ""      ""'])
     #
-    checkViewerEditor('a SVG viewer and editor', [inkscape_name],
+    checkViewerEditor('a SVG viewer and editor', [inkscape_gui],
         rc_entry = [r'''\Format svg        "svg" SVG                "" "%%" "%%"       "vector"        "image/svg+xml"
 \Format svgz       "svgz" "SVG (compressed)" "" "%%" "%%"      "vector,zipped=native"  ""'''],
         path = [inkscape_path])
@@ -604,13 +635,18 @@ def checkFormatEntries(dtl_tools):
 \Format tiff       tif     TIFF                   "" "%s"      "%s"    ""      "image/tiff"
 \Format xbm        xbm     XBM                    "" "%s"      "%s"    ""      "image/x-xbitmap"
 \Format xpm        xpm     XPM                    "" "%s"      "%s"    ""      "image/x-xpixmap"'''
-    path, iv = checkViewerNoRC('a raster image viewer', ['xv', 'kview', 'gimp-remote', 'gimp'], rc_entry = [imageformats])
-    path, ie = checkEditorNoRC('a raster image editor', ['gimp-remote', 'gimp'], rc_entry = [imageformats])
-    addToRC(imageformats % \
-        (iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie) )
-    #
-    checkViewerEditor('a text editor', ['xemacs', 'gvim', 'kedit', 'kwrite', 'kate', \
-        'nedit', 'gedit', 'notepad', 'geany', 'leafpad', 'mousepad'],
+    path, iv = checkViewerNoRC('a raster image viewer',
+        ['xv', 'gwenview', 'kview',
+         'eog', 'xviewer', 'ristretto', 'gpicview', 'lximage-qt',
+         'xdg-open', 'gimp-remote', 'gimp'],
+        rc_entry = [imageformats])
+    path, ie = checkEditorNoRC('a raster image editor',
+        ['gimp-remote', 'gimp'], rc_entry = [imageformats])
+    addToRC(imageformats % ((iv, ie)*10))
+    #
+    checkViewerEditor('a text editor',
+        ['xemacs', 'gvim', 'kedit', 'kwrite', 'kate',
+         'nedit', 'gedit', 'geany', 'leafpad', 'mousepad', 'xed', 'notepad'],
         rc_entry = [r'''\Format asciichess asc    "Plain text (chess output)"  "" ""   "%%"    ""      ""
 \Format docbook    sgml    DocBook                B  ""        "%%"    "document,menu=export"  ""
 \Format docbook-xml xml   "DocBook (XML)"         "" ""        "%%"    "document,menu=export"  "application/docbook+xml"
@@ -619,10 +655,12 @@ def checkFormatEntries(dtl_tools):
 \Format platex     tex    "LaTeX (pLaTeX)"        "" "" "%%"   "document,menu=export"  ""
 \Format literate   nw      NoWeb                  N  ""        "%%"    "document,menu=export"  ""
 \Format sweave     Rnw    "Sweave"                S  "" "%%"   "document,menu=export"  ""
+\Format sweave-ja  Rnw    "Sweave (Japanese)"     S  "" "%%"   "document,menu=export"  ""
 \Format r          R      "R/S code"              "" "" "%%"   "document,menu=export"  ""
 \Format knitr      Rnw    "Rnw (knitr)"           "" "" "%%"   "document,menu=export"  ""
-\Format lilypond   ly     "LilyPond music"        "" ""        "%%"    "vector"        "text/x-lilypond"
+\Format knitr-ja   Rnw    "Rnw (knitr, Japanese)" "" "" "%%"   "document,menu=export"  ""
 \Format lilypond-book    lytex "LilyPond book (LaTeX)"   "" "" "%%"    "document,menu=export"  ""
+\Format lilypond-book-ja lytex "LilyPond book (pLaTeX)"   "" ""        "%%"    "document,menu=export"  ""
 \Format latex      tex    "LaTeX (plain)"         L  ""        "%%"    "document,menu=export"  "text/x-tex"
 \Format luatex     tex    "LaTeX (LuaTeX)"        "" ""        "%%"    "document,menu=export"  ""
 \Format pdflatex   tex    "LaTeX (pdflatex)"      "" ""        "%%"    "document,menu=export"  ""
@@ -634,6 +672,11 @@ def checkFormatEntries(dtl_tools):
 \Format text4      txt    "Plain text (catdvi)"   "" ""        "%%"    "document"      ""
 \Format textparagraph txt "Plain Text, Join Lines" "" ""       "%%"    "document"      ""
 \Format beamer.info pdf.info   "Info (Beamer)"         "" ""   "%%"    "document,menu=export"  ""''' ])
+   #Lilypond files have special editors, but fall back to plain text editors
+    checkViewerEditor('a lilypond editor',
+        ['frescobaldi', 'xemacs', 'gvim', 'kedit', 'kwrite', 'kate',
+         'nedit', 'gedit', 'geany', 'leafpad', 'mousepad', 'xed', 'notepad'],
+        rc_entry = [r'''\Format lilypond   ly     "LilyPond music"        "" ""        "%%"    "vector"        "text/x-lilypond"''' ])
    #Spreadsheets using ssconvert from gnumeric
     checkViewer('gnumeric spreadsheet software', ['gnumeric'],
       rc_entry = [r'''\Format gnumeric gnumeric "Gnumeric spreadsheet" "" ""    "%%"   "document"      "application/x-gnumeric"
@@ -645,25 +688,32 @@ def checkFormatEntries(dtl_tools):
     checkViewer('an HTML previewer', ['firefox', 'mozilla file://$$p$$i', 'netscape'],
         rc_entry = [r'\Format xhtml      xhtml   "LyXHTML"              y "%%" ""    "document,menu=export"    "application/xhtml+xml"'])
  #
-    checkEditor('a BibTeX editor', ['jabref', 'JabRef', \
-        'pybliographic', 'bibdesk', 'gbib', 'kbib', \
-        'kbibtex', 'sixpack', 'bibedit', 'tkbibtex' \
-        'xemacs', 'gvim', 'kedit', 'kwrite', 'kate', \
-        'jedit', 'TeXnicCenter', 'WinEdt', 'WinShell', 'PSPad', \
+    checkEditor('a BibTeX editor', ['jabref', 'JabRef',
+        'pybliographic', 'bibdesk', 'gbib', 'kbib',
+        'kbibtex', 'sixpack', 'bibedit', 'tkbibtex'
+        'xemacs', 'gvim', 'kedit', 'kwrite', 'kate',
+        'jedit', 'TeXnicCenter', 'WinEdt', 'WinShell', 'PSPad',
         'nedit', 'gedit', 'notepad', 'geany', 'leafpad', 'mousepad'],
         rc_entry = [r'''\Format bibtex bib    "BibTeX"         "" ""   "%%"    ""      "text/x-bibtex"''' ])
     #
     #checkProg('a Postscript interpreter', ['gs'],
     #  rc_entry = [ r'\ps_command "%%"' ])
-    checkViewer('a Postscript previewer', ['kghostview', 'okular', 'qpdfview --unique', 'evince', 'gv', 'ghostview -swap', 'gsview64', 'gsview32'],
+    checkViewer('a Postscript previewer',
+                ['kghostview', 'okular', 'qpdfview --unique',
+                 'evince', 'xreader',
+                 'gv', 'ghostview -swap', 'gsview64', 'gsview32'],
         rc_entry = [r'''\Format eps        eps     EPS                    "" "%%"      ""      "vector"        "image/x-eps"
 \Format eps2       eps    "EPS (uncropped)"       "" "%%"      ""      "vector"        ""
 \Format eps3       eps    "EPS (cropped)"         "" "%%"      ""      "document"      ""
 \Format ps         ps      Postscript             t  "%%"      ""      "document,vector,menu=export"   "application/postscript"'''])
     # for xdg-open issues look here: http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg151818.html
+    # maybe use "bestApplication()" from https://github.com/jleclanche/python-mime
     # the MIME type is set for pdf6, because that one needs to be autodetectable by libmime
-    checkViewer('a PDF previewer', ['pdfview', 'kpdf', 'okular', 'qpdfview --unique', 'evince', 'kghostview', 'xpdf', 'SumatraPDF', 'acrobat', 'acroread', 'mupdf', \
-                   'gv', 'ghostview', 'AcroRd32', 'gsview64', 'gsview32'],
+    checkViewer('a PDF previewer',
+                ['pdfview', 'kpdf', 'okular', 'qpdfview --unique',
+                 'evince', 'xreader', 'kghostview', 'xpdf', 'SumatraPDF',
+                 'acrobat', 'acroread', 'mupdf',
+                 'gv', 'ghostview', 'AcroRd32', 'gsview64', 'gsview32'],
         rc_entry = [r'''\Format pdf        pdf    "PDF (ps2pdf)"          P  "%%"      ""      "document,vector,menu=export"   ""
 \Format pdf2       pdf    "PDF (pdflatex)"        F  "%%"      ""      "document,vector,menu=export"   ""
 \Format pdf3       pdf    "PDF (dvipdfm)"         m  "%%"      ""      "document,vector,menu=export"   ""
@@ -673,7 +723,9 @@ def checkFormatEntries(dtl_tools):
 \Format pdf7       pdf    "PDF (cropped)"         "" "%%"      ""      "document,vector"       ""
 \Format pdf8       pdf    "PDF (lower resolution)"         "" "%%"     ""      "document,vector"       ""'''])
     #
-    checkViewer('a DVI previewer', ['xdvi', 'kdvi', 'okular', 'yap', 'dviout -Set=!m'],
+    checkViewer('a DVI previewer', ['xdvi', 'kdvi', 'okular',
+                                    'evince', 'xreader',
+                                    'yap', 'dviout -Set=!m'],
         rc_entry = [r'''\Format dvi        dvi     DVI                    D  "%%"      ""      "document,vector,menu=export"   "application/x-dvi"
 \Format dvi3       dvi     "DVI (LuaTeX)"          V  "%%"     ""      "document,vector,menu=export"   ""'''])
     if dtl_tools:
@@ -724,10 +776,10 @@ def checkFormatEntries(dtl_tools):
 def checkConverterEntries():
     ''' Check all converters (\converter entries) '''
     checkProg('the pdflatex program', ['pdflatex $$i'],
-        rc_entry = [ r'\converter pdflatex   pdf2       "%%"   "latex=pdflatex"' ])
+        rc_entry = [ r'\converter pdflatex   pdf2       "%%"   "latex=pdflatex,hyperref-driver=pdftex"' ])
 
     checkProg('XeTeX', ['xelatex $$i'],
-        rc_entry = [ r'\converter xetex      pdf4       "%%"   "latex=xelatex"' ])
+        rc_entry = [ r'\converter xetex      pdf4       "%%"   "latex=xelatex,hyperref-driver=xetex"' ])
 
     checkLuatex()
 
@@ -745,7 +797,7 @@ def checkConverterEntries():
     in_binary_dir = os.path.join(lyx_binary_dir, 'tex2lyx')
     in_binary_dir = os.path.abspath(in_binary_dir).replace('\\', '/')
 
-    path, t2l = checkProg('a LaTeX/Noweb -> LyX converter', [in_binary_subdir, in_binary_subdir + version_suffix, in_binary_dir, in_binary_dir + version_suffix, 'tex2lyx' + version_suffix, 'tex2lyx'],
+    path, t2l = checkProg('a LaTeX/Noweb -> LyX converter', [quoteIfSpace(in_binary_subdir), quoteIfSpace(in_binary_subdir + version_suffix), quoteIfSpace(in_binary_dir), quoteIfSpace(in_binary_dir + version_suffix), 'tex2lyx' + version_suffix, 'tex2lyx'],
         rc_entry = [r'''\converter latex      lyx        "%% -f $$i $$o"       ""
 \converter latexclipboard lyx        "%% -fixedenc utf8 -f $$i $$o"    ""
 \converter literate   lyx        "%% -n -m noweb -f $$i $$o"   ""
@@ -765,6 +817,7 @@ def checkConverterEntries():
     checkProg('a Sweave -> LaTeX converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxsweave.R $$p$$i $$p$$o $$e $$r'],
         rc_entry = [r'''\converter sweave   latex      "%%"    "needauth"
 \converter sweave   pdflatex   "%%"    "needauth"
+\converter sweave-ja   platex     "%%" "needauth"
 \converter sweave   xetex      "%%"    "needauth"
 \converter sweave   luatex     "%%"    "needauth"
 \converter sweave   dviluatex  "%%"    "needauth"'''])
@@ -772,21 +825,24 @@ def checkConverterEntries():
     checkProg('a knitr -> LaTeX converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxknitr.R $$p$$i $$p$$o $$e $$r'],
         rc_entry = [r'''\converter knitr   latex      "%%"     "needauth"
 \converter knitr   pdflatex   "%%"     "needauth"
+\converter knitr-ja   platex     "%%"  "needauth"
 \converter knitr   xetex      "%%"     "needauth"
 \converter knitr   luatex     "%%"     "needauth"
 \converter knitr   dviluatex  "%%"     "needauth"'''])
     #
-    checkProg('a Sweave -> R/S code converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxstangle.R $$i $$e $$r'], 
-        rc_entry = [ r'\converter sweave      r      "%%"    "needauth"' ])
+    checkProg('a Sweave -> R/S code converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxstangle.R $$i $$e $$r'],
+        rc_entry = [ r'\converter sweave      r      "%%"    ""',
+                     r'\converter sweave-ja   r      "%%"    ""' ])
     #
     checkProg('a knitr -> R/S code converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxknitr.R $$p$$i $$p$$o $$e $$r tangle'],
-        rc_entry = [ r'\converter knitr      r      "%%"    "needauth"' ])
+        rc_entry = [ r'\converter knitr      r      "%%"    ""',
+                     r'\converter knitr-ja   r      "%%"    ""' ])
     #
     checkProg('an HTML -> LaTeX converter', ['html2latex $$i', 'gnuhtml2latex',
         'htmltolatex -input $$i -output $$o', 'htmltolatex.jar -input $$i -output $$o'],
-        rc_entry = [ r'\converter html       latex      "%%"   ""', \
-                     r'\converter html       latex      "python -tt $$s/scripts/html2latexwrapper.py %% $$i $$o"       ""', \
-                     r'\converter html       latex      "%%"   ""', \
+        rc_entry = [ r'\converter html       latex      "%%"   ""',
+                     r'\converter html       latex      "python -tt $$s/scripts/html2latexwrapper.py %% $$i $$o"       ""',
+                     r'\converter html       latex      "%%"   ""',
                      r'\converter html       latex      "%%"   ""', '' ])
     #
     checkProg('an MS Word -> LaTeX converter', ['wvCleanLatex $$i $$o'],
@@ -811,16 +867,16 @@ def checkConverterEntries():
     else:
       # search for HTML converters other than eLyXer
       # On SuSE the scripts have a .sh suffix, and on debian they are in /usr/share/tex4ht/
-      path, htmlconv = checkProg('a LaTeX -> HTML converter', ['htlatex $$i', 'htlatex.sh $$i', \
-          '/usr/share/tex4ht/htlatex $$i', 'tth  -t -e2 -L$$b < $$i > $$o', \
+      path, htmlconv = checkProg('a LaTeX -> HTML converter', ['htlatex $$i', 'htlatex.sh $$i',
+          '/usr/share/tex4ht/htlatex $$i', 'tth  -t -e2 -L$$b < $$i > $$o',
           'latex2html -no_subdir -split 0 -show_section_numbers $$i', 'hevea -s $$i'],
           rc_entry = [ r'\converter latex      html       "%%" "needaux"' ])
       if htmlconv.find('htlatex') >= 0 or htmlconv == 'latex2html':
         addToRC(r'''\copier    html       "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
       else:
         addToRC(r'''\copier    html       "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
-      path, htmlconv = checkProg('a LaTeX -> HTML (MS Word) converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'", \
-          "htlatex.sh $$i 'html,word' 'symbol/!' '-cvalidate'", \
+      path, htmlconv = checkProg('a LaTeX -> HTML (MS Word) converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'",
+          "htlatex.sh $$i 'html,word' 'symbol/!' '-cvalidate'",
           "/usr/share/tex4ht/htlatex $$i 'html,word' 'symbol/!' '-cvalidate'"],
           rc_entry = [ r'\converter latex      wordhtml   "%%" "needaux"' ])
       if htmlconv.find('htlatex') >= 0:
@@ -873,9 +929,9 @@ def checkConverterEntries():
     #
     checkProg('a RTF -> HTML converter', ['unrtf --html  $$i > $$o'],
         rc_entry = [ r'\converter rtf      html        "%%"    ""' ])
-    # Do not define a converter to pdf6, ps is a pure export format 
+    # Do not define a converter to pdf6, ps is a pure export format
     checkProg('a PS to PDF converter', ['ps2pdf $$i $$o'],
-        rc_entry = [ r'\converter ps         pdf        "%%"   ""' ])
+        rc_entry = [ r'\converter ps         pdf        "%%"   "hyperref-driver=dvips"' ])
     #
     checkProg('a PS to TXT converter', ['pstotext $$i > $$o'],
         rc_entry = [ r'\converter ps         text2      "%%"   ""' ])
@@ -897,6 +953,14 @@ def checkConverterEntries():
     # Only define a converter from pdf6 for graphics
     checkProg('a PDF to EPS converter', ['pdftops -eps -f 1 -l 1 $$i $$o'],
         rc_entry = [ r'\converter pdf6        eps        "%%"  ""' ])
+    # Define a converter from pdf6 to png for Macs where pdftops is missing.
+    # The converter utility sips allows to force the dimensions of the resulting
+    # png image. The value of 800 pixel for the width is arbitrary and not
+    # related to the current screen resolution or width.
+    # There is no converter parameter for this information.
+    checkProg('a PDF to PNG converter',
+        ['sips --resampleWidth 800 --setProperty format png $$i --out $$o'],
+        rc_entry = [ r'\converter pdf6        png        "%%" ""' ])
     # Create one converter for a PDF produced using TeX fonts and one for a
     # PDF produced using non-TeX fonts. This does not produce non-unique
     # conversion paths, since a given document either uses TeX fonts or not.
@@ -917,13 +981,13 @@ def checkConverterEntries():
         rc_entry = [ r'\converter dvi        text4      "%%"   ""' ])
     #
     checkProg('a DVI to PS converter', ['dvips -o $$o $$i'],
-        rc_entry = [ r'\converter dvi        ps         "%%"   ""' ])
+        rc_entry = [ r'\converter dvi        ps         "%%"   "hyperref-driver=dvips"' ])
     #
     checkProg('a DVI to cropped EPS converter', ['dvips -E -o $$o $$i'],
         rc_entry = [ r'\converter dvi        eps3         "%%" ""' ])
     #
-    checkProg('a DVI to PDF converter', ['dvipdfmx -o $$o $$i', 'dvipdfm -o $$o $$i'],
-        rc_entry = [ r'\converter dvi        pdf3       "%%"   ""' ])
+    checkProg('a DVI to PDF converter', ['dvipdfmx', 'dvipdfm'],
+        rc_entry = [ r'\converter dvi        pdf3       "%%  -o $$o $$i"       "hyperref-driver=%%"' ])
     #
     checkProg('a fax program', ['kdeprintfax $$i', 'ksendfax $$i', 'hylapex $$i'],
         rc_entry = [ r'\converter ps         fax        "%%"   ""'])
@@ -934,11 +998,17 @@ def checkConverterEntries():
 \converter fig        ppm        "fig2dev -L ppm $$i $$o"      ""
 \converter fig        svg        "fig2dev -L svg $$i $$o"      ""
 \converter fig        png        "fig2dev -L png $$i $$o"      ""
-\converter svg        pdftex     "python -tt $$s/scripts/svg2pdftex.py $$i $$o" ""
-\converter svg        pstex      "python -tt $$s/scripts/svg2pstex.py $$i $$o" ""
 \converter fig        pdftex     "python -tt $$s/scripts/fig2pdftex.py $$i $$o"        ""
 \converter fig        pstex      "python -tt $$s/scripts/fig2pstex.py $$i $$o" ""''')
     #
+    checkProg('a SVG -> PDFTeX converter', [inkscape_cl],
+        rc_entry = [ r'\converter svg        pdftex     "python -tt $$s/scripts/svg2pdftex.py %% $$p$$i $$p$$o" ""'],
+        path = [inkscape_path])
+    #
+    checkProg('a SVG -> PSTeX converter', [inkscape_cl],
+        rc_entry = [ r'\converter svg        pstex     "python -tt $$s/scripts/svg2pstex.py %% $$p$$i $$p$$o" ""'],
+        path = [inkscape_path])
+    #
     checkProg('a TIFF -> PS converter', ['tiff2ps $$i > $$o'],
         rc_entry = [ r'\converter tiff       eps        "%%"   ""'])
     #
@@ -948,16 +1018,18 @@ def checkConverterEntries():
 \converter tgif       png        "tgif -print -color -png -o $$d $$i"  ""
 \converter tgif       pdf6       "tgif -print -color -pdf -stdout $$i > $$o"   ""'''])
     #
-    checkProg('a WMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i', inkscape_name + ' --file=$$i --export-area-drawing --without-gui --export-eps=$$o'],
+    checkProg('a WMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i', inkscape_cl + ' --file=%s$$i --export-area-drawing --without-gui --export-eps=%s$$o'
+               % (inkscape_fileprefix, inkscape_fileprefix)],
         rc_entry = [ r'\converter wmf        eps        "%%"   ""'])
     #
-    checkProg('an EMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i', inkscape_name + ' --file=$$i --export-area-drawing --without-gui --export-eps=$$o'],
+    checkProg('an EMF -> EPS converter', ['metafile2eps $$i $$o', inkscape_cl + ' --file=%s$$i --export-area-drawing --without-gui --export-eps=%s$$o'
+               % (inkscape_fileprefix, inkscape_fileprefix)],
         rc_entry = [ r'\converter emf        eps        "%%"   ""'])
     #
-    checkProg('a WMF -> PDF converter', [inkscape_name + ' --file=$$i --export-area-drawing --without-gui --export-pdf=$$o'],
+    checkProg('a WMF -> PDF converter', [inkscape_cl + ' --file=%s$$i --export-area-drawing --without-gui --export-pdf=%s$$o' % (inkscape_fileprefix, inkscape_fileprefix)],
         rc_entry = [ r'\converter wmf        pdf6        "%%"  ""'])
     #
-    checkProg('an EMF -> PDF converter', [inkscape_name + ' --file=$$i --export-area-drawing --without-gui --export-pdf=$$o'],
+    checkProg('an EMF -> PDF converter', [inkscape_cl + ' --file=%s$$i --export-area-drawing --without-gui --export-pdf=%s$$o' % (inkscape_fileprefix, inkscape_fileprefix)],
         rc_entry = [ r'\converter emf        pdf6        "%%"  ""'])
     # Only define a converter to pdf6 for graphics
     checkProg('an EPS -> PDF converter', ['epstopdf'],
@@ -993,7 +1065,7 @@ def checkConverterEntries():
     # The eps2->eps converter then fixes the bounding box by cropping.
     # Although unoconv can convert to png and pdf as well, do not define
     # odg->png and odg->pdf converters, since the bb would be too large as well.
-    checkProg('an OpenDocument -> EPS converter', ['libreoffice -headless -nologo -convert-to eps $$i', 'unoconv -f eps --stdout $$i > $$o'],
+    checkProg('an OpenDocument -> EPS converter', ['libreoffice --headless --nologo --convert-to eps $$i', 'unoconv -f eps --stdout $$i > $$o'],
         rc_entry = [ r'\converter odg        eps2       "%%"   ""'])
     #
     checkProg('a SVG (compressed) -> SVG converter', ['gunzip -c $$i > $$o'],
@@ -1003,21 +1075,27 @@ def checkConverterEntries():
         rc_entry = [ r'\converter svg        svgz       "%%"   ""'])
     # Only define a converter to pdf6 for graphics
     # Prefer rsvg-convert over inkscape since it is faster (see http://www.lyx.org/trac/ticket/9891)
-    checkProg('a SVG -> PDF converter', ['rsvg-convert -f pdf -o $$o $$i', inkscape_name + ' --file=$$i --export-area-drawing --without-gui --export-pdf=$$o'],
+    checkProg('a SVG -> PDF converter', ['rsvg-convert -f pdf -o $$o $$i', inkscape_cl + ' --file=%s$$i --export-area-drawing --without-gui --export-pdf=%s$$o'
+               % (inkscape_fileprefix, inkscape_fileprefix)],
         rc_entry = [ r'''\converter svg        pdf6       "%%"    ""
 \converter svgz       pdf6       "%%"    ""'''],
         path = ['', inkscape_path])
     #
-    checkProg('a SVG -> EPS converter', ['rsvg-convert -f ps -o $$o $$i', inkscape_name + ' --file=$$i --export-area-drawing --without-gui --export-eps=$$o'],
+    checkProg('a SVG -> EPS converter', ['rsvg-convert -f ps -o $$o $$i', inkscape_cl + ' --file=%s$$i --export-area-drawing --without-gui --export-eps=%s$$o'
+               % (inkscape_fileprefix, inkscape_fileprefix)],
         rc_entry = [ r'''\converter svg        eps        "%%"    ""
 \converter svgz       eps        "%%"    ""'''],
         path = ['', inkscape_path])
     #
-    checkProg('a SVG -> PNG converter', ['rsvg-convert -f png -o $$o $$i', inkscape_name + ' --without-gui --file=$$i --export-png=$$o'],
+    checkProg('a SVG -> PNG converter', ['rsvg-convert -f png -o $$o $$i', inkscape_cl + ' --without-gui --file=%s$$i --export-png=%s$$o'
+               % (inkscape_fileprefix, inkscape_fileprefix)],
         rc_entry = [ r'''\converter svg        png        "%%"    "",
 \converter svgz       png        "%%"    ""'''],
         path = ['', inkscape_path])
-
+    #
+    checkProg('Gnuplot', ['gnuplot'], 
+        rc_entry = [ r'''\Format gnuplot     "gp, gnuplot"    "Gnuplot"     "" "" ""  "vector" "text/plain"
+\converter gnuplot      pdf6      "python -tt $$s/scripts/gnuplot2pdf.py $$i $$o"    "needauth"''' ])
     #
     # gnumeric/xls/ods to tex
     checkProg('a spreadsheet -> latex converter', ['ssconvert'],
@@ -1071,6 +1149,7 @@ def checkConverterEntries():
                 #       this, use different output folders for eps and pdf outputs.
                 addToRC(r'\converter lilypond-book latex    "lilypond-book --safe --lily-output-dir=ly-eps $$i"                                ""')
                 addToRC(r'\converter lilypond-book pdflatex "lilypond-book --safe --pdf --latex-program=pdflatex --lily-output-dir=ly-pdf $$i" ""')
+                addToRC(r'\converter lilypond-book-ja platex "lilypond-book --safe --pdf --latex-program=platex --lily-output-dir=ly-pdf $$i" ""')
                 addToRC(r'\converter lilypond-book xetex    "lilypond-book --safe --pdf --latex-program=xelatex --lily-output-dir=ly-pdf $$i"  ""')
                 addToRC(r'\converter lilypond-book luatex   "lilypond-book --safe --pdf --latex-program=lualatex --lily-output-dir=ly-pdf $$i" ""')
                 addToRC(r'\converter lilypond-book dviluatex "lilypond-book --safe --latex-program=dvilualatex --lily-output-dir=ly-eps $$i" ""')
@@ -1145,20 +1224,27 @@ def checkOtherEntries():
     ''' entries other than Format and Converter '''
     checkProg('ChkTeX', ['chktex -n1 -n3 -n6 -n9 -n22 -n25 -n30 -n38'],
         rc_entry = [ r'\chktex_command "%%"' ])
-    checkProgAlternatives('BibTeX or alternative programs', ['bibtex', 'bibtex8', 'biber'],
-        rc_entry = [ r'\bibtex_command "%%"' ],
+    checkProgAlternatives('BibTeX or alternative programs',
+        ['bibtex', 'bibtex8', 'biber'],
+        rc_entry = [ r'\bibtex_command "automatic"' ],
         alt_rc_entry = [ r'\bibtex_alternatives "%%"' ])
-    checkProg('a specific Japanese BibTeX variant', ['pbibtex', 'jbibtex', 'bibtex'],
-        rc_entry = [ r'\jbibtex_command "%%"' ])
-    checkProgAlternatives('available index processors', ['texindy', 'makeindex -c -q', 'xindy'],
+    checkProgAlternatives('a specific Japanese BibTeX variant',
+        ['pbibtex', 'upbibtex', 'jbibtex', 'bibtex', 'biber'],
+        rc_entry = [ r'\jbibtex_command "automatic"' ],
+        alt_rc_entry = [ r'\jbibtex_alternatives "%%"' ])
+    checkProgAlternatives('available index processors',
+        ['texindy', 'makeindex -c -q', 'xindy'],
         rc_entry = [ r'\index_command "%%"' ],
         alt_rc_entry = [ r'\index_alternatives "%%"' ])
-    checkProg('an index processor appropriate to Japanese', ['mendex -c -q', 'jmakeindex -c -q', 'makeindex -c -q'],
+    checkProg('an index processor appropriate to Japanese',
+        ['mendex -c -q', 'jmakeindex -c -q', 'makeindex -c -q'],
         rc_entry = [ r'\jindex_command "%%"' ])
     checkProg('the splitindex processor', ['splitindex.pl', 'splitindex',
         'splitindex.class'], rc_entry = [ r'\splitindex_command "%%"' ])
     checkProg('a nomenclature processor', ['makeindex'],
         rc_entry = [ r'\nomencl_command "makeindex -s nomencl.ist"' ])
+    checkProg('a python-pygments driver command', ['pygmentize'],
+        rc_entry = [ r'\pygmentize_command "%%"' ])
     ## FIXME: OCTAVE is not used anywhere
     # path, OCTAVE = checkProg('Octave', ['octave'])
     ## FIXME: MAPLE is not used anywhere
@@ -1177,19 +1263,19 @@ def processLayoutFile(file, bool_docbook):
         Declare lines look like this:
 
         \DeclareLaTeXClass[<requirements>]{<description>}
-        
+
         Optionally, a \DeclareCategory line follows:
-        
+
         \DeclareCategory{<category>}
-        
+
         So for example (article.layout, scrbook.layout, svjog.layout)
-        
+
         \DeclareLaTeXClass{article}
         \DeclareCategory{Articles}
-        
+
         \DeclareLaTeXClass[scrbook]{book (koma-script)}
         \DeclareCategory{Books}
-        
+
         \DeclareLaTeXClass[svjour,svjog.clo]{article (Springer - svjour/jog)}
 
         we'd expect this output:
@@ -1201,42 +1287,43 @@ def processLayoutFile(file, bool_docbook):
     def checkForClassExtension(x):
         '''if the extension for a latex class is not
            provided, add .cls to the classname'''
-        if not '.' in x:
-            return x.strip() + '.cls'
+        if not b'.' in x:
+            return x.strip() + b'.cls'
         else:
             return x.strip()
     classname = file.split(os.sep)[-1].split('.')[0]
     # return ('LaTeX', '[a,b]', 'a', ',b,c', 'article') for \DeclareLaTeXClass[a,b,c]{article}
-    p = re.compile(r'^\s*#\s*\\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}\s*$')
-    q = re.compile(r'^\s*#\s*\\DeclareCategory{(.*)}\s*$')
-    classdeclaration = ""
-    categorydeclaration = '""'
-    for line in open(file).readlines():
+    p = re.compile(b'^\s*#\s*\\\\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}\s*$')
+    q = re.compile(b'^\s*#\s*\\\\DeclareCategory{(.*)}\s*$')
+    classdeclaration = b""
+    categorydeclaration = b'""'
+    for line in open(file, 'rb').readlines():
         res = p.search(line)
         qres = q.search(line)
         if res != None:
             (classtype, optAll, opt, opt1, desc) = res.groups()
-            avai = {'LaTeX':'false', 'DocBook':bool_docbook}[classtype]
+            avai = {b'LaTeX':b'false', b'DocBook':bool_docbook.encode('ascii')}[classtype]
             if opt == None:
-                opt = classname
-                prereq_latex = checkForClassExtension(classname)
+                opt = classname.encode('ascii')
+                prereq_latex = checkForClassExtension(classname.encode('ascii'))
             else:
-                prereq_list = optAll[1:-1].split(',')
+                prereq_list = optAll[1:-1].split(b',')
                 prereq_list = list(map(checkForClassExtension, prereq_list))
-                prereq_latex = ','.join(prereq_list)
-            prereq_docbook = {'true':'', 'false':'docbook'}[bool_docbook]
-            prereq = {'LaTeX':prereq_latex, 'DocBook':prereq_docbook}[classtype]
-            classdeclaration = '"%s" "%s" "%s" "%s" "%s"' % (classname, opt, desc, avai, prereq)
-            if categorydeclaration != '""':
-                return classdeclaration + " " + categorydeclaration
+                prereq_latex = b','.join(prereq_list)
+            prereq_docbook = {'true':b'', 'false':b'docbook'}[bool_docbook]
+            prereq = {b'LaTeX':prereq_latex, b'DocBook':prereq_docbook}[classtype]
+            classdeclaration = (b'"%s" "%s" "%s" "%s" "%s"'
+                               % (classname, opt, desc, avai, prereq))
+            if categorydeclaration != b'""':
+                return classdeclaration + b" " + categorydeclaration
         if qres != None:
-             categorydeclaration = '"%s"' % (qres.groups()[0])
-             if classdeclaration != "":
-                 return classdeclaration + " " + categorydeclaration
-    if classdeclaration != "":
-        return classdeclaration + " " + categorydeclaration
+             categorydeclaration = b'"%s"' % (qres.groups()[0])
+             if classdeclaration != b"":
+                 return classdeclaration + b" " + categorydeclaration
+    if classdeclaration != b"":
+        return classdeclaration + b" " + categorydeclaration
     logger.warning("Layout file " + file + " has no \DeclareXXClass line. ")
-    return ""
+    return b""
 
 
 def checkLatexConfig(check_config, bool_docbook):
@@ -1254,8 +1341,8 @@ def checkLatexConfig(check_config, bool_docbook):
         # fails, we still have something to start lyx.
         logger.info(msg + ' default values')
         logger.info('+checking list of textclasses... ')
-        tx = open('textclass.lst', 'w')
-        tx.write('''
+        tx = open('textclass.lst', 'wb')
+        tx.write(b'''
 # This file declares layouts and their associated definition files
 # (include dir. relative to the place where this file is).
 # It contains only default values, since chkconfig.ltx could not be run
@@ -1265,8 +1352,8 @@ def checkLatexConfig(check_config, bool_docbook):
         # build the list of available layout files and convert it to commands
         # for chkconfig.ltx
         foundClasses = []
-        for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
-            glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
+        for file in (glob.glob(os.path.join('layouts', '*.layout'))
+                     + glob.glob(os.path.join(srcdir, 'layouts', '*.layout'))):
             # valid file?
             if not os.path.isfile(file):
                 continue
@@ -1279,8 +1366,8 @@ def checkLatexConfig(check_config, bool_docbook):
             if foundClasses.count(cleanclass) == 0: # not found before
                 foundClasses.append(cleanclass)
                 retval = processLayoutFile(file, bool_docbook)
-                if retval != "":
-                    tx.write(retval)
+                if retval != b"":
+                    tx.write(retval + os.linesep)
         tx.close()
         logger.info('\tdone')
     if not os.path.isfile('packages.lst') or not check_config:
@@ -1303,40 +1390,44 @@ def checkLatexConfig(check_config, bool_docbook):
     # Construct the list of classes to test for.
     # build the list of available layout files and convert it to commands
     # for chkconfig.ltx
-    declare = re.compile(r'^\s*#\s*\\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}\s*$')
-    category = re.compile(r'^\s*#\s*\\DeclareCategory{(.*)}\s*$')
-    empty = re.compile(r'^\s*$')
+    declare = re.compile(b'^\\s*#\\s*\\\\Declare(LaTeX|DocBook)Class\\s*(\[([^,]*)(,.*)*\])*\\s*{(.*)}\\s*$')
+    category = re.compile(b'^\\s*#\\s*\\\\DeclareCategory{(.*)}\\s*$')
+    empty = re.compile(b'^\\s*$')
     testclasses = list()
-    for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
-        glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
+    for file in (glob.glob( os.path.join('layouts', '*.layout') )
+                 + glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) ):
         nodeclaration = False
         if not os.path.isfile(file):
             continue
         classname = file.split(os.sep)[-1].split('.')[0]
-        decline = ""
-        catline = ""
-        for line in open(file).readlines():
-            if not empty.match(line) and line[0] != '#':
-                if decline == "":
-                    logger.warning("Failed to find valid \Declare line for layout file `" + file + "'.\n\t=> Skipping this file!")
+        decline = b""
+        catline = b""
+        for line in open(file, 'rb').readlines():
+            if not empty.match(line) and line[0] != b'#'[0]:
+                if decline == b"":
+                    logger.warning("Failed to find valid \Declare line "
+                        "for layout file `%s'.\n\t=> Skipping this file!" % file)
                     nodeclaration = True
                 # A class, but no category declaration. Just break.
                 break
             if declare.search(line) != None:
-                decline = "\\TestDocClass{%s}{%s}" % (classname, line[1:].strip())
+                decline = b"\\TestDocClass{%s}{%s}" \
+                           % (classname.encode('ascii'), line[1:].strip())
                 testclasses.append(decline)
             elif category.search(line) != None:
-                catline = "\\DeclareCategory{%s}{%s}" % (classname, category.search(line).groups()[0])
+                catline = (b"\\DeclareCategory{%s}{%s}"
+                           % (classname.encode('ascii'),
+                              category.search(line).groups()[0]))
                 testclasses.append(catline)
-            if catline == "" or decline == "":
+            if catline == b"" or decline == b"":
                 continue
             break
         if nodeclaration:
             continue
     testclasses.sort()
-    cl = open('chklayouts.tex', 'w')
+    cl = open('chklayouts.tex', 'wb')
     for line in testclasses:
-        cl.write(line + '\n')
+        cl.write(line + b'\n')
     cl.close()
     #
     # we have chklayouts.tex, then process it
@@ -1368,8 +1459,10 @@ def checkLatexConfig(check_config, bool_docbook):
         pass
     # if configure successed, move textclass.lst.tmp to textclass.lst
     # and packages.lst.tmp to packages.lst
-    if os.path.isfile('textclass.lst.tmp') and len(open('textclass.lst.tmp').read()) > 0 \
-        and os.path.isfile('packages.lst.tmp') and len(open('packages.lst.tmp').read()) > 0:
+    if (os.path.isfile('textclass.lst.tmp')
+          and len(open('textclass.lst.tmp').read()) > 0
+        and os.path.isfile('packages.lst.tmp')
+          and len(open('packages.lst.tmp').read()) > 0):
         shutil.move('textclass.lst.tmp', 'textclass.lst')
         shutil.move('packages.lst.tmp', 'packages.lst')
     return ret
@@ -1379,8 +1472,8 @@ def checkModulesConfig():
   removeFiles(['lyxmodules.lst', 'chkmodules.tex'])
 
   logger.info('+checking list of modules... ')
-  tx = open('lyxmodules.lst', 'w')
-  tx.write('''## This file declares modules and their associated definition files.
+  tx = open('lyxmodules.lst', 'wb')
+  tx.write(b'''## This file declares modules and their associated definition files.
 ## It has been automatically generated by configure
 ## Use "Options/Reconfigure" if you need to update it after a
 ## configuration change.
@@ -1391,8 +1484,8 @@ def checkModulesConfig():
   seen = []
   # note that this searches the local directory first, then the
   # system directory. that way, we pick up the user's version first.
-  for file in glob.glob( os.path.join('layouts', '*.module') ) + \
-      glob.glob( os.path.join(srcdir, 'layouts', '*.module' ) ) :
+  for file in (glob.glob( os.path.join('layouts', '*.module') )
+               + glob.glob( os.path.join(srcdir, 'layouts', '*.module' ) ) ):
       # valid file?
       logger.info(file)
       if not os.path.isfile(file):
@@ -1404,8 +1497,8 @@ def checkModulesConfig():
           continue
 
       seen.append(filename)
-      retval = processModuleFile(file, filename, bool_docbook)
-      if retval != "":
+      retval = processModuleFile(file, filename.encode('ascii'), bool_docbook)
+      if retval != b"":
           tx.write(retval)
   tx.close()
   logger.info('\tdone')
@@ -1426,25 +1519,25 @@ def processModuleFile(file, filename, bool_docbook):
         We expect output:
           "ModuleName" "filename" "Description" "Packages" "Requires" "Excludes" "Category"
     '''
-    remods = re.compile(r'\DeclareLyXModule\s*(?:\[([^]]*?)\])?{(.*)}')
-    rereqs = re.compile(r'#+\s*Requires: (.*)')
-    reexcs = re.compile(r'#+\s*Excludes: (.*)')
-    recaty = re.compile(r'#+\s*Category: (.*)')
-    redbeg = re.compile(r'#+\s*DescriptionBegin\s*$')
-    redend = re.compile(r'#+\s*DescriptionEnd\s*$')
-
-    modname = desc = pkgs = req = excl = catgy = ""
+    remods = re.compile(b'\\\\DeclareLyXModule\s*(?:\[([^]]*?)\])?{(.*)}')
+    rereqs = re.compile(b'#+\s*Requires: (.*)')
+    reexcs = re.compile(b'#+\s*Excludes: (.*)')
+    recaty = re.compile(b'#+\s*Category: (.*)')
+    redbeg = re.compile(b'#+\s*DescriptionBegin\s*$')
+    redend = re.compile(b'#+\s*DescriptionEnd\s*$')
+
+    modname = desc = pkgs = req = excl = catgy = b""
     readingDescription = False
     descLines = []
 
-    for line in open(file).readlines():
+    for line in open(file, 'rb').readlines():
       if readingDescription:
         res = redend.search(line)
         if res != None:
           readingDescription = False
-          desc = " ".join(descLines)
+          desc = b" ".join(descLines)
           # Escape quotes.
-          desc = desc.replace('"', '\\"')
+          desc = desc.replace(b'"', b'\\"')
           continue
         descLines.append(line[1:].strip())
         continue
@@ -1456,58 +1549,59 @@ def processModuleFile(file, filename, bool_docbook):
       if res != None:
           (pkgs, modname) = res.groups()
           if pkgs == None:
-            pkgs = ""
+            pkgs = b""
           else:
-            tmp = [s.strip() for s in pkgs.split(",")]
-            pkgs = ",".join(tmp)
+            tmp = [s.strip() for s in pkgs.split(b",")]
+            pkgs = b",".join(tmp)
           continue
       res = rereqs.search(line)
       if res != None:
         req = res.group(1)
-        tmp = [s.strip() for s in req.split("|")]
-        req = "|".join(tmp)
+        tmp = [s.strip() for s in req.split(b"|")]
+        req = b"|".join(tmp)
         continue
       res = reexcs.search(line)
       if res != None:
         excl = res.group(1)
-        tmp = [s.strip() for s in excl.split("|")]
-        excl = "|".join(tmp)
+        tmp = [s.strip() for s in excl.split(b"|")]
+        excl = b"|".join(tmp)
         continue
       res = recaty.search(line)
       if res != None:
         catgy = res.group(1)
         continue
 
-    if modname == "":
+    if modname == b"":
       logger.warning("Module file without \DeclareLyXModule line. ")
-      return ""
+      return b""
 
-    if pkgs != "":
+    if pkgs != b"":
         # this module has some latex dependencies:
         # append the dependencies to chkmodules.tex,
         # which is \input'ed by chkconfig.ltx
         testpackages = list()
-        for pkg in pkgs.split(","):
-            if "->" in pkg:
+        for pkg in pkgs.split(b","):
+            if b"->" in pkg:
                 # this is a converter dependency: skip
                 continue
-            if pkg.endswith(".sty"):
+            if pkg.endswith(b".sty"):
                 pkg = pkg[:-4]
-            testpackages.append("\\TestPackage{%s}" % (pkg,))
+            testpackages.append("\\TestPackage{%s}" % (pkg.decode('ascii'),))
         cm = open('chkmodules.tex', 'a')
         for line in testpackages:
             cm.write(line + '\n')
         cm.close()
 
-    return '"%s" "%s" "%s" "%s" "%s" "%s" "%s"\n' % (modname, filename, desc, pkgs, req, excl, catgy)
+    return (b'"%s" "%s" "%s" "%s" "%s" "%s" "%s"\n'
+            % (modname, filename, desc, pkgs, req, excl, catgy))
 
 
 def checkCiteEnginesConfig():
   removeFiles(['lyxciteengines.lst', 'chkciteengines.tex'])
 
   logger.info('+checking list of cite engines... ')
-  tx = open('lyxciteengines.lst', 'w')
-  tx.write('''## This file declares cite engines and their associated definition files.
+  tx = open('lyxciteengines.lst', 'wb')
+  tx.write(b'''## This file declares cite engines and their associated definition files.
 ## It has been automatically generated by configure
 ## Use "Options/Reconfigure" if you need to update it after a
 ## configuration change.
@@ -1531,8 +1625,8 @@ def checkCiteEnginesConfig():
           continue
 
       seen.append(filename)
-      retval = processCiteEngineFile(file, filename, bool_docbook)
-      if retval != "":
+      retval = processCiteEngineFile(file, filename.encode('ascii'), bool_docbook)
+      if retval != b"":
           tx.write(retval)
   tx.close()
   logger.info('\tdone')
@@ -1549,25 +1643,25 @@ def processCiteEngineFile(file, filename, bool_docbook):
         We expect output:
           "CiteEngineName" "filename" "CiteEngineType" "CiteFramework" "DefaultBiblio" "Description" "Packages"
     '''
-    remods = re.compile(r'\DeclareLyXCiteEngine\s*(?:\[([^]]*?)\])?{(.*)}')
-    redbeg = re.compile(r'#+\s*DescriptionBegin\s*$')
-    redend = re.compile(r'#+\s*DescriptionEnd\s*$')
-    recet = re.compile(r'\s*CiteEngineType\s*(.*)')
-    redb = re.compile(r'\s*DefaultBiblio\s*(.*)')
-    resfm = re.compile(r'\s*CiteFramework\s*(.*)')
+    remods = re.compile(b'\\\\DeclareLyXCiteEngine\s*(?:\[([^]]*?)\])?{(.*)}')
+    redbeg = re.compile(b'#+\s*DescriptionBegin\s*$')
+    redend = re.compile(b'#+\s*DescriptionEnd\s*$')
+    recet = re.compile(b'\s*CiteEngineType\s*(.*)')
+    redb = re.compile(b'\s*DefaultBiblio\s*(.*)')
+    resfm = re.compile(b'\s*CiteFramework\s*(.*)')
 
     modname = desc = pkgs = cet = db = cfm = ""
     readingDescription = False
     descLines = []
 
-    for line in open(file).readlines():
+    for line in open(file, 'rb').readlines():
       if readingDescription:
         res = redend.search(line)
         if res != None:
           readingDescription = False
-          desc = " ".join(descLines)
+          desc = b" ".join(descLines)
           # Escape quotes.
-          desc = desc.replace('"', '\\"')
+          desc = desc.replace(b'"', b'\\"')
           continue
         descLines.append(line[1:].strip())
         continue
@@ -1579,10 +1673,10 @@ def processCiteEngineFile(file, filename, bool_docbook):
       if res != None:
           (pkgs, modname) = res.groups()
           if pkgs == None:
-            pkgs = ""
+            pkgs = b""
           else:
-            tmp = [s.strip() for s in pkgs.split(",")]
-            pkgs = ",".join(tmp)
+            tmp = [s.strip() for s in pkgs.split(b",")]
+            pkgs = b",".join(tmp)
           continue
       res = recet.search(line)
       if res != None:
@@ -1597,28 +1691,61 @@ def processCiteEngineFile(file, filename, bool_docbook):
         cfm = res.group(1)
         continue
 
-    if modname == "":
+    if modname == b"":
       logger.warning("Cite Engine File file without \DeclareLyXCiteEngine line. ")
-      return ""
+      return b""
 
-    if pkgs != "":
+    if pkgs != b"":
         # this cite engine has some latex dependencies:
         # append the dependencies to chkciteengines.tex,
         # which is \input'ed by chkconfig.ltx
         testpackages = list()
-        for pkg in pkgs.split(","):
-            if "->" in pkg:
+        for pkg in pkgs.split(b","):
+            if b"->" in pkg:
                 # this is a converter dependency: skip
                 continue
-            if pkg.endswith(".sty"):
+            if pkg.endswith(b".sty"):
                 pkg = pkg[:-4]
-            testpackages.append("\\TestPackage{%s}" % (pkg,))
+            testpackages.append("\\TestPackage{%s}" % (pkg.decode('ascii'),))
         cm = open('chkciteengines.tex', 'a')
         for line in testpackages:
             cm.write(line + '\n')
         cm.close()
 
-    return '"%s" "%s" "%s" "%s" "%s" "%s" "%s"\n' % (modname, filename, cet, cfm, db, desc, pkgs)
+    return (b'"%s" "%s" "%s" "%s" "%s" "%s" "%s"\n' % (modname, filename, cet, cfm, db, desc, pkgs))
+
+
+def checkXTemplates():
+  removeFiles(['xtemplates.lst'])
+
+  logger.info('+checking list of external templates... ')
+  tx = open('xtemplates.lst', 'w')
+  tx.write('''## This file lists external templates.
+## It has been automatically generated by configure
+## Use "Options/Reconfigure" if you need to update it after a
+## configuration change.
+''')
+
+  # build the list of available templates
+  seen = []
+  # note that this searches the local directory first, then the
+  # system directory. that way, we pick up the user's version first.
+  for file in glob.glob( os.path.join('xtemplates', '*.xtemplate') ) + \
+      glob.glob( os.path.join(srcdir, 'xtemplates', '*.xtemplate' ) ) :
+      # valid file?
+      logger.info(file)
+      if not os.path.isfile(file):
+          continue
+
+      filename = file.split(os.sep)[-1]
+      if seen.count(filename):
+          continue
+
+      seen.append(filename)
+      if filename != "":
+          tx.write(filename + "\n")
+  tx.close()
+  logger.info('\tdone')
 
 
 def checkTeXAllowSpaces():
@@ -1647,13 +1774,14 @@ def checkTeXAllowSpaces():
 def rescanTeXFiles():
     ''' Run kpsewhich to update information about TeX files '''
     logger.info("+Indexing TeX files... ")
-    if not os.path.isfile( os.path.join(srcdir, 'scripts', 'TeXFiles.py') ):
+    tfscript = os.path.join(srcdir, 'scripts', 'TeXFiles.py')
+    if not os.path.isfile(tfscript):
         logger.error("configure: error: cannot find TeXFiles.py script")
         sys.exit(1)
     interpreter = sys.executable
     if interpreter == '':
         interpreter = "python"
-    tfp = cmdOutput(interpreter + " -tt " + '"' + os.path.join(srcdir, 'scripts', 'TeXFiles.py') + '"')
+    tfp = cmdOutput('"%s" -tt "%s"' % (interpreter, tfscript))
     logger.info(tfp)
     logger.info("\tdone")
 
@@ -1670,7 +1798,7 @@ if __name__ == '__main__':
     lyx_check_config = True
     lyx_kpsewhich = True
     outfile = 'lyxrc.defaults'
-    lyxrc_fileformat = 20
+    lyxrc_fileformat = 24
     rc_entries = ''
     lyx_keep_temps = False
     version_suffix = ''
@@ -1730,7 +1858,17 @@ Format %i
     # check java and perl before any checkProg that may require them
     java = checkProg('a java interpreter', ['java'])[1]
     perl = checkProg('a perl interpreter', ['perl'])[1]
-    (inkscape_path, inkscape_name) = os.path.split(checkInkscape())
+    (inkscape_path, inkscape_gui) = os.path.split(checkInkscape())
+    # On Windows, we need to call the "inkscape.com" wrapper
+    # for command line purposes. Other OSes do not differentiate.
+    inkscape_cl = inkscape_gui
+    if os.name == 'nt':
+        inkscape_cl = inkscape_gui.replace('.exe', '.com')
+    # On MacOSX, Inkscape requires full path file arguments. This
+    # is not needed on Linux and Win and even breaks the latter.
+    inkscape_fileprefix = ""
+    if sys.platform == 'darwin':
+        inkscape_fileprefix = "$$p"
     checkFormatEntries(dtl_tools)
     checkConverterEntries()
     (chk_docbook, bool_docbook, docbook_cmd) = checkDocBook()
@@ -1743,6 +1881,7 @@ Format %i
         rescanTeXFiles()
     checkModulesConfig()
     checkCiteEnginesConfig()
+    checkXTemplates()
     # --without-latex-config can disable lyx_check_config
     ret = checkLatexConfig(lyx_check_config and LATEX != '', bool_docbook)
     removeTempFiles()