]> git.lyx.org Git - lyx.git/blobdiff - src/support/filetools.cpp
Get rid of regex_constants::match_partial
[lyx.git] / src / support / filetools.cpp
index 727c0dffe6f2db1f0ce2f40c0e84cb709283e094..040272aade620e406bed47dcca8947126c0c763d 100644 (file)
@@ -8,11 +8,11 @@
  * \author Ivan Schreter
  * \author Dirk Niggemann
  * \author Asger Alstrup
- * \author Lars Gullik Bjønnes
+ * \author Lars Gullik Bjønnes
  * \author Jean-Marc Lasgouttes
  * \author Angus Leeming
  * \author John Levon
- * \author Herbert Voß
+ * \author Herbert Voß
  *
  * Full author contact details are available in file CREDITS.
  *
 
 #include <config.h>
 
-#include "support/convert.h"
-#include "support/environment.h"
+#include "LyXRC.h"
+
 #include "support/filetools.h"
-#include "support/fs_extras.h"
+
+#include "support/debug.h"
+#include "support/environment.h"
+#include "support/gettext.h"
 #include "support/lstrings.h"
-#include "support/lyxlib.h"
 #include "support/os.h"
+#include "support/Messages.h"
 #include "support/Package.h"
-#include "support/Path.h"
+#include "support/PathChanger.h"
 #include "support/Systemcall.h"
+#include "support/qstring_helpers.h"
 
-// FIXME Interface violation
-#include "gettext.h"
-#include "debug.h"
+#include <QDir>
+#include <QTemporaryFile>
 
-#include <boost/assert.hpp>
-#include <boost/filesystem/operations.hpp>
-#include <boost/regex.hpp>
+#include "support/lassert.h"
+#include "support/regex.h"
 
 #include <fcntl.h>
+#ifdef HAVE_MAGIC_H
+#include <magic.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
 #include <cerrno>
 #include <cstdlib>
 #include <utility>
 #include <fstream>
 #include <sstream>
+#include <vector>
 
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#ifdef HAVE_DIRECT_H
-# include <direct.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif
-#ifdef HAVE_IO_H
-# include <io.h>
-#endif
-#ifdef HAVE_SYS_UTIME_H
-# include <sys/utime.h>
-#endif
-#ifdef HAVE_UTIME_H
-# include <utime.h>
-#endif
-
-#include "zip.h"
-#include "unzip.h"
-
-#ifdef WIN32
-#define USEWIN32IOAPI
-#include "iowin32.h"
-#endif
-
-#define WRITEBUFFERSIZE (16384)
-#define MAXFILENAME (256)
-
-
-#ifndef CXX_GLOBAL_CSTD
-using std::fgetc;
+#if defined (_WIN32)
+#include <io.h>
+#include <windows.h>
 #endif
 
-using std::endl;
-using std::getline;
-using std::make_pair;
-using std::string;
-using std::ifstream;
-using std::ostringstream;
-using std::vector;
-using std::pair;
+using namespace std;
 
-namespace fs = boost::filesystem;
+#define USE_QPROCESS
 
 namespace lyx {
 namespace support {
 
-bool isLyXFilename(string const & filename)
+bool isLyXFileName(string const & filename)
 {
        return suffixIs(ascii_lowercase(filename), ".lyx");
 }
 
 
-bool isSGMLFilename(string const & filename)
+bool isSGMLFileName(string const & filename)
 {
        return suffixIs(ascii_lowercase(filename), ".sgml");
 }
 
 
-bool isValidLaTeXFilename(string const & filename)
+bool isValidLaTeXFileName(string const & filename)
 {
-       string const invalid_chars("#$%{}()[]\"^");
-       if (filename.find_first_of(invalid_chars) != string::npos)
-               return false;
-       else
-               return true;
+       string const invalid_chars("#%\"");
+       return filename.find_first_of(invalid_chars) == string::npos;
+}
+
+
+bool isValidDVIFileName(string const & filename)
+{
+       string const invalid_chars("${}()[]^");
+       return filename.find_first_of(invalid_chars) == string::npos;
+}
+
+
+bool isBinaryFile(FileName const & filename)
+{
+       bool isbinary = false;
+       if (filename.empty() || !filename.exists())
+               return isbinary;
+
+#ifdef HAVE_MAGIC_H
+       magic_t magic_cookie = magic_open(MAGIC_MIME_ENCODING);
+       if (magic_cookie) {
+               bool detected = true;
+               if (magic_load(magic_cookie, NULL) != 0) {
+                       LYXERR(Debug::FILES, "isBinaryFile: "
+                               "Could not load magic database - "
+                               << magic_error(magic_cookie));
+                       detected = false;
+               } else {
+                       char const *charset = magic_file(magic_cookie,
+                                       filename.toFilesystemEncoding().c_str());
+                       isbinary = contains(charset, "binary");
+               }
+               magic_close(magic_cookie);
+               if (detected)
+                       return isbinary;
+       }
+#endif
+       // Try by looking for binary chars at the beginning of the file.
+       // Note that this is formally not correct, since count_bin_chars
+       // expects utf8, and the passed string can be anything: plain text
+       // in any encoding, or really binary data. In practice it works,
+       // since QString::fromUtf8() drops invalid utf8 sequences, and
+       // while the exact number may not be correct, we still get a high
+       // number for truly binary files.
+
+       ifstream ifs(filename.toFilesystemEncoding().c_str());
+       if (!ifs)
+               return isbinary;
+
+       // Maximum strings to read
+       int const max_count = 50;
+
+       // Maximum number of binary chars allowed
+       int const max_bin = 5;
+
+       int count = 0;
+       int binchars = 0;
+       string str;
+       while (count++ < max_count && !ifs.eof()) {
+               getline(ifs, str);
+               binchars += count_bin_chars(str);
+       }
+       return binchars > max_bin;
 }
 
 
@@ -135,13 +162,13 @@ string const latex_path(string const & original_path,
                // We can't use '"' because " is sometimes active (e.g. if
                // babel is loaded with the "german" option)
                if (extension == EXCLUDE_EXTENSION) {
-                       // ChangeExtension calls os::internal_path internally
+                       // changeExtension calls os::internal_path internally
                        // so don't use it to remove the extension.
                        string const ext = getExtension(path);
                        string const base = ext.empty() ?
                                path :
                                path.substr(0, path.length() - ext.length() - 1);
-                       // ChangeExtension calls os::internal_path internally
+                       // changeExtension calls os::internal_path internally
                        // so don't use it to re-add the extension.
                        path = "\\string\"" + base + "\\string\"." + ext;
                } else {
@@ -149,17 +176,30 @@ string const latex_path(string const & original_path,
                }
        }
 
-       return dots == ESCAPE_DOTS ? subst(path, ".", "\\lyxdot ") : path;
+       if (dots != ESCAPE_DOTS)
+               return path;
+
+       // Replace dots with the lyxdot macro, but only in the file name,
+       // not the directory part.
+       // addName etc call os::internal_path internally
+       // so don't use them for path manipulation
+       // The directory separator is always '/' for LaTeX.
+       string::size_type pos = path.rfind('/');
+       if (pos == string::npos)
+               return subst(path, ".", "\\lyxdot ");
+       return path.substr(0, pos) + subst(path.substr(pos), ".", "\\lyxdot ");
 }
 
 
 // Substitutes spaces with underscores in filename (and path)
-string const makeLatexName(string const & file)
+FileName const makeLatexName(FileName const & file)
 {
-       string name = onlyFilename(file);
-       string const path = onlyPath(file);
+       string name = file.onlyFileName();
+       string const path = file.onlyPath().absFileName() + "/";
 
        // ok so we scan through the string twice, but who cares.
+       // FIXME: in Unicode time this will break for sure! There is
+       // a non-latin world out there...
        string const keep = "abcdefghijklmnopqrstuvwxyz"
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                "@!'()*+,-./0123456789:;<=>?[]`|";
@@ -168,7 +208,9 @@ string const makeLatexName(string const & file)
        while ((pos = name.find_first_not_of(keep, pos)) != string::npos)
                name[pos++] = '_';
 
-       return addName(path, name);
+       FileName latex_name(path + name);
+       latex_name.changeExtension(".tex");
+       return latex_name;
 }
 
 
@@ -176,16 +218,29 @@ string const quoteName(string const & name, quote_style style)
 {
        switch(style) {
        case quote_shell:
-               // This does not work for filenames containing " (windows)
-               // or ' (all other OSes). This can't be changed easily, since
-               // we would need to adapt the command line parser in
-               // Forkedcall::generateChild. Therefore we don't pass user
-               // filenames to child processes if possible. We store them in
-               // a python script instead, where we don't have these
-               // limitations.
+               // This does not work on native Windows for filenames
+               // containing the following characters < > : " / \ | ? *
+               // Moreover, it can't be made to work, as, according to
+               // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
+               // those are reserved characters, and thus are forbidden.
+               // Please, also note that the command-line parser in
+               // ForkedCall::generateChild cannot deal with filenames
+               // containing " or ', therefore we don't pass user filenames
+               // to child processes if possible. We store them in a python
+               // script instead, where we don't have these limitations.
+#ifndef USE_QPROCESS
                return (os::shell() == os::UNIX) ?
-                       '\'' + name + '\'':
+                       '\'' + subst(name, "'", "\'\\\'\'") + '\'' :
                        '"' + name + '"';
+#else
+               // According to the QProcess parser, a single double
+               // quote is represented by three consecutive ones.
+               // Here we simply escape the double quote and let our
+               // simple parser in Systemcall.cpp do the substitution.
+               return '"' + subst(name, "\"", "\\\"") + '"';
+#endif
+       case quote_shell_filename:
+               return quoteName(os::external_path(name), quote_shell);
        case quote_python:
                return "\"" + subst(subst(name, "\\", "\\\\"), "\"", "\\\"")
                     + "\"";
@@ -195,29 +250,6 @@ string const quoteName(string const & name, quote_style style)
 }
 
 
-bool isFileReadable(FileName const & filename)
-{
-       std::string const path = filename.toFilesystemEncoding();
-       return fs::exists(path) && !fs::is_directory(path) && fs::is_readable(path);
-}
-
-
-//returns true: dir writeable
-//       false: not writeable
-bool isDirWriteable(FileName const & path)
-{
-       LYXERR(Debug::FILES) << "isDirWriteable: " << path << endl;
-
-       FileName const tmpfl(tempName(path, "lyxwritetest"));
-
-       if (tmpfl.empty())
-               return false;
-
-       unlink(tmpfl);
-       return true;
-}
-
-
 #if 0
 // Uses a string of paths separated by ";"s to find a file to open.
 // Can't cope with pathnames with a ';' in them. Returns full path to file.
@@ -237,9 +269,9 @@ FileName const fileOpenSearch(string const & path, string const & name,
                if (!suffixIs(path_element, '/'))
                        path_element += '/';
                path_element = subst(path_element, "$$LyX",
-                                    package().system_support().absFilename());
+                                    package().system_support().absFileName());
                path_element = subst(path_element, "$$User",
-                                    package().user_support().absFilename());
+                                    package().user_support().absFileName());
 
                real_file = fileSearch(path_element, name, ext);
 
@@ -256,37 +288,6 @@ FileName const fileOpenSearch(string const & path, string const & name,
 #endif
 
 
-/// Returns a vector of all files in directory dir having extension ext.
-vector<FileName> const dirList(FileName const & dir, string const & ext)
-{
-       // EXCEPTIONS FIXME. Rewrite needed when we turn on exceptions. (Lgb)
-       vector<FileName> dirlist;
-
-       string const encoded_dir = dir.toFilesystemEncoding();
-       if (!(fs::exists(encoded_dir) && fs::is_directory(encoded_dir))) {
-               LYXERR(Debug::FILES)
-                       << "Directory \"" << dir
-                       << "\" does not exist to DirList." << endl;
-               return dirlist;
-       }
-
-       string extension;
-       if (!ext.empty() && ext[0] != '.')
-               extension += '.';
-       extension += ext;
-
-       fs::directory_iterator dit(encoded_dir);
-       fs::directory_iterator end;
-       for (; dit != end; ++dit) {
-               string const & fil = dit->leaf();
-               if (suffixIs(fil, extension))
-                       dirlist.push_back(FileName::fromFilesystemEncoding(
-                                       encoded_dir + '/' + fil));
-       }
-       return dirlist;
-}
-
-
 // Returns the real name of file name in directory path, with optional
 // extension ext.
 FileName const fileSearch(string const & path, string const & name,
@@ -297,16 +298,22 @@ FileName const fileSearch(string const & path, string const & name,
        string const tmpname = replaceEnvironmentPath(name);
        FileName fullname(makeAbsPath(tmpname, path));
        // search first without extension, then with it.
-       if (isFileReadable(fullname))
+       if (fullname.isReadableFile())
                return fullname;
        if (ext.empty())
                // We are done.
-               return mode == allow_unreadable ? fullname : FileName();
+               return mode == may_not_exist ? fullname : FileName();
        // Only add the extension if it is not already the extension of
        // fullname.
-       if (getExtension(fullname.absFilename()) != ext)
-               fullname = FileName(addExtension(fullname.absFilename(), ext));
-       if (isFileReadable(fullname) || mode == allow_unreadable)
+       if (getExtension(fullname.absFileName()) != ext) {
+               if (mode == check_hidpi) {
+                       FileName fullname2x = FileName(addExtension(fullname.absFileName() + "@2x", ext));
+                       if (fullname2x.isReadableFile())
+                               return fullname2x;
+               }
+               fullname = FileName(addExtension(fullname.absFileName(), ext));
+       }
+       if (fullname.isReadableFile() || mode == may_not_exist)
                return fullname;
        return FileName();
 }
@@ -317,20 +324,21 @@ FileName const fileSearch(string const & path, string const & name,
 //   2) build_lyxdir (if not empty)
 //   3) system_lyxdir
 FileName const libFileSearch(string const & dir, string const & name,
-                          string const & ext)
+                          string const & ext, search_mode mode)
 {
-       FileName fullname = fileSearch(addPath(package().user_support().absFilename(), dir),
-                                    name, ext);
+       FileName fullname = fileSearch(addPath(package().user_support().absFileName(), dir),
+                                    name, ext, mode);
        if (!fullname.empty())
                return fullname;
 
        if (!package().build_support().empty())
-               fullname = fileSearch(addPath(package().build_support().absFilename(), dir),
-                                     name, ext);
+               fullname = fileSearch(addPath(package().build_support().absFileName(), dir),
+                                     name, ext, mode);
        if (!fullname.empty())
                return fullname;
 
-       return fileSearch(addPath(package().system_support().absFilename(), dir), name, ext);
+       return fileSearch(addPath(package().system_support().absFileName(), dir),
+                                     name, ext, mode);
 }
 
 
@@ -341,11 +349,11 @@ FileName const i18nLibFileSearch(string const & dir, string const & name,
           variable. But we don't use the value if the currently
           selected locale is the C locale. This is a GNU extension.
 
-          Otherwise, w use a trick to guess what gettext has done:
+          Otherwise, w use a trick to guess what support/gettext.has done:
           each po file is able to tell us its name. (JMarc)
        */
 
-       string lang = to_ascii(_("[[Replace with the code of your language]]"));
+       string lang = getGuiMessages().language();
        string const language = getEnv("LANGUAGE");
        if (!lang.empty() && !language.empty())
                lang = language;
@@ -384,11 +392,30 @@ FileName const i18nLibFileSearch(string const & dir, string const & name,
 }
 
 
-string const libScriptSearch(string const & command_in, quote_style style)
+FileName const imageLibFileSearch(string & dir, string const & name,
+                 string const & ext, search_mode mode)
+{
+       if (!lyx::lyxrc.icon_set.empty()) {
+               string const imagedir = addPath(dir, lyx::lyxrc.icon_set);
+               FileName const fn = libFileSearch(imagedir, name, ext, mode);
+               if (fn.exists()) {
+                       dir = imagedir;
+                       return fn;
+               }
+       }
+       return libFileSearch(dir, name, ext, mode);
+}
+
+
+string const commandPrep(string const & command_in)
 {
        static string const token_scriptpath = "$$s/";
+       string const python_call = "python -tt";
 
        string command = command_in;
+       if (prefixIs(command_in, python_call))
+               command = os::python() + command_in.substr(python_call.length());
+
        // Find the starting position of "$$s/"
        string::size_type const pos1 = command.find(token_scriptpath);
        if (pos1 == string::npos)
@@ -402,12 +429,16 @@ string const libScriptSearch(string const & command_in, quote_style style)
 
        // Does this script file exist?
        string const script =
-               libFileSearch(".", command.substr(start_script, size_script)).absFilename();
+               libFileSearch(".", command.substr(start_script, size_script)).absFileName();
 
        if (script.empty()) {
                // Replace "$$s/" with ""
                command.erase(pos1, 4);
        } else {
+               quote_style style = quote_shell;
+               if (prefixIs(command, os::python()))
+                       style = quote_python;
+
                // Replace "$$s/foo/some_script" with "<path to>/some_script".
                string::size_type const size_replace = size_script + 4;
                command.replace(pos1, size_replace, quoteName(script, style));
@@ -417,88 +448,63 @@ string const libScriptSearch(string const & command_in, quote_style style)
 }
 
 
-namespace {
-
-FileName const createTmpDir(FileName const & tempdir, string const & mask)
+static string createTempFile(QString const & mask)
 {
-       LYXERR(Debug::FILES)
-               << "createTmpDir: tempdir=`" << tempdir << "'\n"
-               << "createTmpDir:    mask=`" << mask << '\'' << endl;
-
-       FileName const tmpfl(tempName(tempdir, mask));
-       // lyx::tempName actually creates a file to make sure that it
-       // stays unique. So we have to delete it before we can create
-       // a dir with the same name. Note also that we are not thread
-       // safe because of the gap between unlink and mkdir. (Lgb)
-       unlink(tmpfl);
-
-       if (tmpfl.empty() || mkdir(tmpfl, 0700)) {
-               lyxerr << "LyX could not create the temporary directory '"
-                      << tmpfl << "'" << endl;
-               return FileName();
+       // FIXME: This is not safe. QTemporaryFile creates a file in open(),
+       //        but the file is deleted when qt_tmp goes out of scope.
+       //        Therefore the next call to createTempFile() may create the
+       //        same file again. To make this safe the QTemporaryFile object
+       //        needs to be kept for the whole life time of the temp file name.
+       //        This could be achieved by creating a class TempDir (like
+       //        TempFile, but using a currentlky non-existing
+       //        QTemporaryDirectory object).
+       QTemporaryFile qt_tmp(mask + ".XXXXXXXXXXXX");
+       if (qt_tmp.open()) {
+               string const temp_file = fromqstr(qt_tmp.fileName());
+               LYXERR(Debug::FILES, "Temporary file `" << temp_file << "' created.");
+               return temp_file;
        }
-
-       return tmpfl;
+       LYXERR(Debug::FILES, "Unable to create temporary file with following template: "
+                       << qt_tmp.fileTemplate());
+       return string();
 }
 
-} // namespace anon
 
-
-bool destroyDir(FileName const & tmpdir)
+static FileName createTmpDir(FileName const & tempdir, string const & mask)
 {
-       try {
-               return fs::remove_all(tmpdir.toFilesystemEncoding()) > 0;
-       } catch (fs::filesystem_error const & fe){
-               lyxerr << "Could not delete " << tmpdir << ". (" << fe.what() << ")" << std::endl;
-               return false;
-       }
-}
+       LYXERR(Debug::FILES, "createTmpDir: tempdir=`" << tempdir << "'\n"
+               << "createTmpDir:    mask=`" << mask << '\'');
 
+       QFileInfo tmp_fi(QDir(toqstr(tempdir.absFileName())), toqstr(mask));
+       FileName const tmpfl(createTempFile(tmp_fi.absoluteFilePath()));
 
-string const createBufferTmpDir()
-{
-       static int count;
-       // We are in our own directory.  Why bother to mangle name?
-       // In fact I wrote this code to circumvent a problematic behaviour
-       // (bug?) of EMX mkstemp().
-       string const tmpfl =
-               package().temp_dir().absFilename() + "/lyx_tmpbuf" +
-               convert<string>(count++);
-
-       if (mkdir(FileName(tmpfl), 0777)) {
-               lyxerr << "LyX could not create the temporary directory '"
-                      << tmpfl << "'" << endl;
-               return string();
+       if (tmpfl.empty() || !tmpfl.createDirectory(0700)) {
+               LYXERR0("LyX could not create temporary directory in " << tempdir
+                       << "'");
+               return FileName();
        }
+
        return tmpfl;
 }
 
 
 FileName const createLyXTmpDir(FileName const & deflt)
 {
-       if (!deflt.empty() && deflt.absFilename() != "/tmp") {
-               if (mkdir(deflt, 0777)) {
-                       if (isDirWriteable(deflt)) {
-                               // deflt could not be created because it
-                               // did exist already, so let's create our own
-                               // dir inside deflt.
-                               return createTmpDir(deflt, "lyx_tmpdir");
-                       } else {
-                               // some other error occured.
-                               return createTmpDir(FileName("/tmp"), "lyx_tmpdir");
-                       }
-               } else
-                       return deflt;
-       } else {
-               return createTmpDir(FileName("/tmp"), "lyx_tmpdir");
-       }
-}
+       if (deflt.empty() || deflt == package().system_temp_dir())
+               return createTmpDir(package().system_temp_dir(), "lyx_tmpdir");
 
+       if (deflt.createDirectory(0777))
+               return deflt;
 
-bool createDirectory(FileName const & path, int permission)
-{
-       BOOST_ASSERT(!path.empty());
-       return mkdir(path, permission) == 0;
+       if (deflt.isDirWritable()) {
+               // deflt could not be created because it
+               // did exist already, so let's create our own
+               // dir inside deflt.
+               return createTmpDir(deflt, "lyx_tmpdir");
+       } else {
+               // some other error occured.
+               return createTmpDir(package().system_temp_dir(), "lyx_tmpdir");
+       }
 }
 
 
@@ -510,7 +516,7 @@ string const onlyPath(string const & filename)
                return filename;
 
        // Find last / or start of filename
-       string::size_type j = filename.rfind('/');
+       size_t j = filename.rfind('/');
        return j == string::npos ? "./" : filename.substr(0, j + 1);
 }
 
@@ -518,10 +524,14 @@ string const onlyPath(string const & filename)
 // Convert relative path into absolute path based on a basepath.
 // If relpath is absolute, just use that.
 // If basepath is empty, use CWD as base.
+// Note that basePath can be a relative path, in the sense that it may
+// not begin with "/" (e.g.), but it should NOT contain such constructs
+// as "/../".
+// FIXME It might be nice if the code didn't simply assume that.
 FileName const makeAbsPath(string const & relPath, string const & basePath)
 {
        // checks for already absolute path
-       if (os::is_absolute_path(relPath))
+       if (FileName::isAbsolute(relPath))
                return FileName(relPath);
 
        // Copies given paths
@@ -531,10 +541,10 @@ FileName const makeAbsPath(string const & relPath, string const & basePath)
 
        string tempBase;
 
-       if (os::is_absolute_path(basePath))
+       if (FileName::isAbsolute(basePath))
                tempBase = basePath;
        else
-               tempBase = addPath(getcwd().absFilename(), basePath);
+               tempBase = addPath(FileName::getcwd().absFileName(), basePath);
 
        // Handle /./ at the end of the path
        while (suffixIs(tempBase, "/./"))
@@ -544,6 +554,15 @@ FileName const makeAbsPath(string const & relPath, string const & basePath)
        string rTemp = tempRel;
        string temp;
 
+       // Check for a leading "~"
+       // Split by first /
+       rTemp = split(rTemp, temp, '/');
+       if (temp == "~") {
+               tempBase = Package::get_home_dir().absFileName();
+               tempRel = rTemp;
+       }
+
+       rTemp = tempRel;
        while (!rTemp.empty()) {
                // Split by next /
                rTemp = split(rTemp, temp, '/');
@@ -551,15 +570,22 @@ FileName const makeAbsPath(string const & relPath, string const & basePath)
                if (temp == ".") continue;
                if (temp == "..") {
                        // Remove one level of TempBase
-                       string::difference_type i = tempBase.length() - 2;
-                       if (i < 0)
-                               i = 0;
+                       if (tempBase.length() <= 1) {
+                               //this is supposed to be an absolute path, so...
+                               tempBase = "/";
+                               continue;
+                       }
+                       //erase a trailing slash if there is one
+                       if (suffixIs(tempBase, "/"))
+                               tempBase.erase(tempBase.length() - 1, string::npos);
+
+                       string::size_type i = tempBase.length() - 1;
                        while (i > 0 && tempBase[i] != '/')
                                --i;
                        if (i > 0)
                                tempBase.erase(i, string::npos);
                        else
-                               tempBase += '/';
+                               tempBase = '/';
                } else if (temp.empty() && !rTemp.empty()) {
                                tempBase = os::current_root() + rTemp;
                                rTemp.erase();
@@ -572,7 +598,7 @@ FileName const makeAbsPath(string const & relPath, string const & basePath)
        }
 
        // returns absolute path
-       return FileName(os::internal_path(tempBase));
+       return FileName(tempBase);
 }
 
 
@@ -581,7 +607,7 @@ FileName const makeAbsPath(string const & relPath, string const & basePath)
 // Chops any path of filename.
 string const addName(string const & path, string const & fname)
 {
-       string const basename = onlyFilename(fname);
+       string const basename = onlyFileName(fname);
        string buf;
 
        if (path != "." && path != "./" && !path.empty()) {
@@ -595,7 +621,7 @@ string const addName(string const & path, string const & fname)
 
 
 // Strips path from filename
-string const onlyFilename(string const & fname)
+string const onlyFileName(string const & fname)
 {
        if (fname.empty())
                return fname;
@@ -609,20 +635,13 @@ string const onlyFilename(string const & fname)
 }
 
 
-/// Returns true is path is absolute
-bool absolutePath(string const & path)
-{
-       return os::is_absolute_path(path);
-}
-
-
 // Create absolute path. If impossible, don't do anything
 // Supports ./ and ~/. Later we can add support for ~logname/. (Asger)
 string const expandPath(string const & path)
 {
        // checks for already absolute path
        string rTemp = replaceEnvironmentPath(path);
-       if (os::is_absolute_path(rTemp))
+       if (FileName::isAbsolute(rTemp))
                return rTemp;
 
        string temp;
@@ -632,54 +651,19 @@ string const expandPath(string const & path)
        rTemp = split(rTemp, temp, '/');
 
        if (temp == ".")
-               return getcwd().absFilename() + '/' + rTemp;
+               return FileName::getcwd().absFileName() + '/' + rTemp;
 
        if (temp == "~")
-               return package().home_dir().absFilename() + '/' + rTemp;
+               return Package::get_home_dir().absFileName() + '/' + rTemp;
 
        if (temp == "..")
-               return makeAbsPath(copy).absFilename();
+               return makeAbsPath(copy).absFileName();
 
        // Don't know how to handle this
        return copy;
 }
 
 
-// Normalize a path. Constracts path/../path
-// Can't handle "../../" or "/../" (Asger)
-// Also converts paths like /foo//bar ==> /foo/bar
-string const normalizePath(string const & path)
-{
-       // Normalize paths like /foo//bar ==> /foo/bar
-       static boost::regex regex("/{2,}");
-       string const tmppath = boost::regex_merge(path, regex, "/");
-
-       fs::path const npath = fs::path(tmppath, fs::no_check).normalize();
-
-       if (!npath.is_complete())
-               return "./" + npath.string() + '/';
-
-       return npath.string() + '/';
-}
-
-
-string const getFileContents(FileName const & fname)
-{
-       string const encodedname = fname.toFilesystemEncoding();
-       if (fs::exists(encodedname)) {
-               ifstream ifs(encodedname.c_str());
-               ostringstream ofs;
-               if (ifs && ofs) {
-                       ofs << ifs.rdbuf();
-                       ifs.close();
-                       return ofs.str();
-               }
-       }
-       lyxerr << "LyX was not able to read file '" << fname << '\'' << endl;
-       return string();
-}
-
-
 // Search the string for ${VAR} and $VAR and replace VAR using getenv.
 string const replaceEnvironmentPath(string const & path)
 {
@@ -688,27 +672,88 @@ string const replaceEnvironmentPath(string const & path)
        static string const envvar_br = "[$]\\{([A-Za-z_][A-Za-z_0-9]*)\\}";
 
        // $VAR is defined as:
-       // $\{[A-Za-z_][A-Za-z_0-9]*\}
+       // $[A-Za-z_][A-Za-z_0-9]*
        static string const envvar = "[$]([A-Za-z_][A-Za-z_0-9]*)";
 
-       static boost::regex envvar_br_re("(.*)" + envvar_br + "(.*)");
-       static boost::regex envvar_re("(.*)" + envvar + "(.*)");
-       boost::smatch what;
-
+       static regex const envvar_br_re("(.*)" + envvar_br + "(.*)");
+       static regex const envvar_re("(.*)" + envvar + "(.*)");
        string result = path;
        while (1) {
-               regex_match(result, what, envvar_br_re);
-               if (!what[0].matched) {
-                       regex_match(result, what, envvar_re);
-                       if (!what[0].matched)
+               smatch what;
+               if (!regex_match(result, what, envvar_br_re)) {
+                       if (!regex_match(result, what, envvar_re))
                                break;
                }
-               result = what.str(1) + getEnv(what.str(2)) + what.str(3);
+               string env_var = getEnv(what.str(2));
+               result = what.str(1) + env_var + what.str(3);
        }
        return result;
 }
 
 
+// Return a command prefix for setting the environment of the TeX engine.
+string latexEnvCmdPrefix(string const & path)
+{
+       if (path.empty() || lyxrc.texinputs_prefix.empty())
+               return string();
+
+       string const texinputs_prefix = os::latex_path_list(
+                       replaceCurdirPath(path, lyxrc.texinputs_prefix));
+       string const sep = string(1, os::path_separator(os::TEXENGINE));
+       string const texinputs = getEnv("TEXINPUTS");
+
+       if (os::shell() == os::UNIX)
+               return "env TEXINPUTS=\"." + sep + texinputs_prefix
+                                         + sep + texinputs + "\" ";
+       else
+#ifndef USE_QPROCESS
+               return "cmd /d /c set \"TEXINPUTS=."
+                                               + sep + texinputs_prefix
+                                               + sep + texinputs + "\"&";
+#else
+               return "cmd /d /c set \"\"\"TEXINPUTS=."
+                                               + sep + texinputs_prefix
+                                               + sep + texinputs + "\"\"\"&";
+#endif
+}
+
+
+// Replace current directory in all elements of a path list with a given path.
+string const replaceCurdirPath(string const & path, string const & pathlist)
+{
+       string const oldpathlist = replaceEnvironmentPath(pathlist);
+       char const sep = os::path_separator();
+       string newpathlist;
+
+       for (size_t i = 0, k = 0; i != string::npos; k = i) {
+               i = oldpathlist.find(sep, i);
+               string p = oldpathlist.substr(k, i - k);
+               if (FileName::isAbsolute(p)) {
+                       newpathlist += p;
+               } else if (i > k) {
+                       size_t offset = 0;
+                       if (p == ".") {
+                               offset = 1;
+                       } else if (prefixIs(p, "./")) {
+                               offset = 2;
+                               while (p[offset] == '/')
+                                       ++offset;
+                       }
+                       newpathlist += addPath(path, p.substr(offset));
+                       if (suffixIs(p, "//"))
+                               newpathlist += '/';
+               }
+               if (i != string::npos) {
+                       newpathlist += sep;
+                       // Stop here if the last element is empty 
+                       if (++i == oldpathlist.length())
+                               break;
+               }
+       }
+       return newpathlist;
+}
+
+
 // Make relative path out of two absolute paths
 docstring const makeRelPath(docstring const & abspath, docstring const & basepath)
 // Makes relative path out of absolute path. If it is deeper than basepath,
@@ -822,201 +867,12 @@ string const getExtension(string const & name)
 }
 
 
-// the different filetypes and what they contain in one of the first lines
-// (dots are any characters).          (Herbert 20020131)
-// AGR Grace...
-// BMP BM...
-// EPS %!PS-Adobe-3.0 EPSF...
-// FIG #FIG...
-// FITS ...BITPIX...
-// GIF GIF...
-// JPG JFIF
-// PDF %PDF-...
-// PNG .PNG...
-// PBM P1... or P4     (B/W)
-// PGM P2... or P5     (Grayscale)
-// PPM P3... or P6     (color)
-// PS  %!PS-Adobe-2.0 or 1.0,  no "EPSF"!
-// SGI \001\332...     (decimal 474)
-// TGIF        %TGIF...
-// TIFF        II... or MM...
-// XBM ..._bits[]...
-// XPM /* XPM */    sometimes missing (f.ex. tgif-export)
-//      ...static char *...
-// XWD \000\000\000\151        (0x00006900) decimal 105
-//
-// GZIP        \037\213        http://www.ietf.org/rfc/rfc1952.txt
-// ZIP PK...                   http://www.halyava.ru/document/ind_arch.htm
-// Z   \037\235                UNIX compress
-
-string const getFormatFromContents(FileName const & filename)
-{
-       // paranoia check
-       if (filename.empty() || !isFileReadable(filename))
-               return string();
-
-       ifstream ifs(filename.toFilesystemEncoding().c_str());
-       if (!ifs)
-               // Couldn't open file...
-               return string();
-
-       // gnuzip
-       static string const gzipStamp = "\037\213";
-
-       // PKZIP
-       static string const zipStamp = "PK";
-
-       // compress
-       static string const compressStamp = "\037\235";
-
-       // Maximum strings to read
-       int const max_count = 50;
-       int count = 0;
-
-       string str;
-       string format;
-       bool firstLine = true;
-       while ((count++ < max_count) && format.empty()) {
-               if (ifs.eof()) {
-                       LYXERR(Debug::GRAPHICS)
-                               << "filetools(getFormatFromContents)\n"
-                               << "\tFile type not recognised before EOF!"
-                               << endl;
-                       break;
-               }
-
-               getline(ifs, str);
-               string const stamp = str.substr(0, 2);
-               if (firstLine && str.size() >= 2) {
-                       // at first we check for a zipped file, because this
-                       // information is saved in the first bytes of the file!
-                       // also some graphic formats which save the information
-                       // in the first line, too.
-                       if (prefixIs(str, gzipStamp)) {
-                               format =  "gzip";
-
-                       } else if (stamp == zipStamp) {
-                               format =  "zip";
-
-                       } else if (stamp == compressStamp) {
-                               format =  "compress";
-
-                       // the graphics part
-                       } else if (stamp == "BM") {
-                               format =  "bmp";
-
-                       } else if (stamp == "\001\332") {
-                               format =  "sgi";
-
-                       // PBM family
-                       // Don't need to use str.at(0), str.at(1) because
-                       // we already know that str.size() >= 2
-                       } else if (str[0] == 'P') {
-                               switch (str[1]) {
-                               case '1':
-                               case '4':
-                                       format =  "pbm";
-                                   break;
-                               case '2':
-                               case '5':
-                                       format =  "pgm";
-                                   break;
-                               case '3':
-                               case '6':
-                                       format =  "ppm";
-                               }
-                               break;
-
-                       } else if ((stamp == "II") || (stamp == "MM")) {
-                               format =  "tiff";
-
-                       } else if (prefixIs(str,"%TGIF")) {
-                               format =  "tgif";
-
-                       } else if (prefixIs(str,"#FIG")) {
-                               format =  "fig";
-
-                       } else if (prefixIs(str,"GIF")) {
-                               format =  "gif";
-
-                       } else if (str.size() > 3) {
-                               int const c = ((str[0] << 24) & (str[1] << 16) &
-                                              (str[2] << 8)  & str[3]);
-                               if (c == 105) {
-                                       format =  "xwd";
-                               }
-                       }
-
-                       firstLine = false;
-               }
-
-               if (!format.empty())
-                   break;
-               else if (contains(str,"EPSF"))
-                       // dummy, if we have wrong file description like
-                       // %!PS-Adobe-2.0EPSF"
-                       format = "eps";
-
-               else if (contains(str, "Grace"))
-                       format = "agr";
-
-               else if (contains(str, "JFIF"))
-                       format = "jpg";
-
-               else if (contains(str, "%PDF"))
-                       format = "pdf";
-
-               else if (contains(str, "PNG"))
-                       format = "png";
-
-               else if (contains(str, "%!PS-Adobe")) {
-                       // eps or ps
-                       ifs >> str;
-                       if (contains(str,"EPSF"))
-                               format = "eps";
-                       else
-                           format = "ps";
-               }
-
-               else if (contains(str, "_bits[]"))
-                       format = "xbm";
-
-               else if (contains(str, "XPM") || contains(str, "static char *"))
-                       format = "xpm";
-
-               else if (contains(str, "BITPIX"))
-                       format = "fits";
-       }
-
-       if (!format.empty()) {
-               LYXERR(Debug::GRAPHICS)
-                       << "Recognised Fileformat: " << format << endl;
-               return format;
-       }
-
-       LYXERR(Debug::GRAPHICS)
-               << "filetools(getFormatFromContents)\n"
-               << "\tCouldn't find a known format!\n";
-       return string();
-}
-
-
-/// check for zipped file
-bool zippedFile(FileName const & name)
-{
-       string const type = getFormatFromContents(name);
-       if (contains("gzip zip compress", type) && !type.empty())
-               return true;
-       return false;
-}
-
-
 string const unzippedFileName(string const & zipped_file)
 {
        string const ext = getExtension(zipped_file);
        if (ext == "gz" || ext == "z" || ext == "Z")
                return changeExtension(zipped_file, string());
-       return "unzipped_" + zipped_file;
+       return onlyPath(zipped_file) + "unzipped_" + onlyFileName(zipped_file);
 }
 
 
@@ -1042,12 +898,12 @@ docstring const makeDisplayPath(string const & path, unsigned int threshold)
        string str = path;
 
        // If file is from LyXDir, display it as if it were relative.
-       string const system = package().system_support().absFilename();
+       string const system = package().system_support().absFileName();
        if (prefixIs(str, system) && str != system)
                return from_utf8("[" + str.erase(0, system.length()) + "]");
 
        // replace /home/blah with ~/
-       string const home = package().home_dir().absFilename();
+       string const home = Package::get_home_dir().absFileName();
        if (!home.empty() && prefixIs(str, home))
                str = subst(str, home, "~");
 
@@ -1055,45 +911,66 @@ docstring const makeDisplayPath(string const & path, unsigned int threshold)
                return from_utf8(os::external_path(str));
 
        string const prefix = ".../";
-       string temp;
+       docstring dstr = from_utf8(str);
+       docstring temp;
 
-       while (str.length() > threshold)
-               str = split(str, temp, '/');
+       while (dstr.length() > threshold)
+               dstr = split(dstr, temp, '/');
 
        // Did we shorten everything away?
-       if (str.empty()) {
+       if (dstr.empty()) {
                // Yes, filename itself is too long.
                // Pick the start and the end of the filename.
-               str = onlyFilename(path);
-               string const head = str.substr(0, threshold / 2 - 3);
+               dstr = from_utf8(onlyFileName(path));
+               docstring const head = dstr.substr(0, threshold / 2 - 3);
 
-               string::size_type len = str.length();
-               string const tail =
-                       str.substr(len - threshold / 2 - 2, len - 1);
-               str = head + "..." + tail;
+               docstring::size_type len = dstr.length();
+               docstring const tail =
+                       dstr.substr(len - threshold / 2 - 2, len - 1);
+               dstr = head + from_ascii("...") + tail;
        }
 
-       return from_utf8(os::external_path(prefix + str));
+       return from_utf8(os::external_path(prefix + to_utf8(dstr)));
 }
 
 
+#ifdef HAVE_READLINK
 bool readLink(FileName const & file, FileName & link)
 {
-#ifdef HAVE_READLINK
-       char linkbuffer[512];
-       // Should be PATH_MAX but that needs autconf support
        string const encoded = file.toFilesystemEncoding();
-       int const nRead = ::readlink(encoded.c_str(),
+#ifdef HAVE_DEF_PATH_MAX
+       char linkbuffer[PATH_MAX + 1];
+       ssize_t const nRead = ::readlink(encoded.c_str(),
                                     linkbuffer, sizeof(linkbuffer) - 1);
        if (nRead <= 0)
                return false;
        linkbuffer[nRead] = '\0'; // terminator
-       link = makeAbsPath(linkbuffer, onlyPath(file.absFilename()));
+#else
+       vector<char> buf(1024);
+       int nRead = -1;
+
+       while (true) {
+               nRead = ::readlink(encoded.c_str(), &buf[0], buf.size() - 1);
+               if (nRead < 0) {
+                       return false;
+               }
+               if (static_cast<size_t>(nRead) < buf.size() - 1) {
+                       break;
+               }
+               buf.resize(buf.size() * 2);
+       }
+       buf[nRead] = '\0'; // terminator
+       const char * linkbuffer = &buf[0];
+#endif
+       link = makeAbsPath(linkbuffer, onlyPath(file.absFileName()));
        return true;
+}
 #else
+bool readLink(FileName const &, FileName &)
+{
        return false;
-#endif
 }
+#endif
 
 
 cmd_ret const runCommand(string const & cmd)
@@ -1108,7 +985,55 @@ cmd_ret const runCommand(string const & cmd)
        // pstream (process stream), with the
        // variants ipstream, opstream
 
-#if defined (HAVE_POPEN)
+#if defined (_WIN32)
+       int fno;
+       STARTUPINFO startup;
+       PROCESS_INFORMATION process;
+       SECURITY_ATTRIBUTES security;
+       HANDLE in, out;
+       FILE * inf = 0;
+       bool err2out = false;
+       string command;
+       string const infile = trim(split(cmd, command, '<'), " \"");
+       command = rtrim(command);
+       if (suffixIs(command, "2>&1")) {
+               command = rtrim(command, "2>&1");
+               err2out = true;
+       }
+       string const cmdarg = "/d /c " + command;
+       string const comspec = getEnv("COMSPEC");
+
+       security.nLength = sizeof(SECURITY_ATTRIBUTES);
+       security.bInheritHandle = TRUE;
+       security.lpSecurityDescriptor = NULL;
+
+       if (CreatePipe(&in, &out, &security, 0)) {
+               memset(&startup, 0, sizeof(STARTUPINFO));
+               memset(&process, 0, sizeof(PROCESS_INFORMATION));
+
+               startup.cb = sizeof(STARTUPINFO);
+               startup.dwFlags = STARTF_USESTDHANDLES;
+
+               startup.hStdError = err2out ? out : GetStdHandle(STD_ERROR_HANDLE);
+               startup.hStdInput = infile.empty()
+                       ? GetStdHandle(STD_INPUT_HANDLE)
+                       : CreateFile(infile.c_str(), GENERIC_READ,
+                               FILE_SHARE_READ, &security, OPEN_EXISTING,
+                               FILE_ATTRIBUTE_NORMAL, NULL);
+               startup.hStdOutput = out;
+
+               if (startup.hStdInput != INVALID_HANDLE_VALUE &&
+                       CreateProcess(comspec.c_str(), (LPTSTR)cmdarg.c_str(),
+                               &security, &security, TRUE, CREATE_NO_WINDOW,
+                               0, 0, &startup, &process)) {
+
+                       CloseHandle(process.hThread);
+                       fno = _open_osfhandle((long)in, _O_RDONLY);
+                       CloseHandle(out);
+                       inf = _fdopen(fno, "r");
+               }
+       }
+#elif defined (HAVE_POPEN)
        FILE * inf = ::popen(cmd.c_str(), os::popen_read_mode());
 #elif defined (HAVE__POPEN)
        FILE * inf = ::_popen(cmd.c_str(), os::popen_read_mode());
@@ -1116,7 +1041,7 @@ cmd_ret const runCommand(string const & cmd)
 #error No popen() function.
 #endif
 
-       // (Claus Hentschel) Check if popen was succesful ;-)
+       // (Claus Hentschel) Check if popen was successful ;-)
        if (!inf) {
                lyxerr << "RunCommand:: could not start child process" << endl;
                return make_pair(-1, string());
@@ -1129,7 +1054,13 @@ cmd_ret const runCommand(string const & cmd)
                c = fgetc(inf);
        }
 
-#if defined (HAVE_PCLOSE)
+#if defined (_WIN32)
+       WaitForSingleObject(process.hProcess, INFINITE);
+       if (!infile.empty())
+               CloseHandle(startup.hStdInput);
+       CloseHandle(process.hProcess);
+       int const pret = fclose(inf);
+#elif defined (HAVE_PCLOSE)
        int const pret = pclose(inf);
 #elif defined (HAVE__PCLOSE)
        int const pret = _pclose(inf);
@@ -1158,10 +1089,10 @@ FileName const findtexfile(string const & fil, string const & /*format*/)
        // If the file can be found directly, we just return a
        // absolute path version of it.
        FileName const absfile(makeAbsPath(fil));
-       if (fs::exists(absfile.toFilesystemEncoding()))
+       if (absfile.exists())
                return absfile;
 
-       // No we try to find it using kpsewhich.
+       // Now we try to find it using kpsewhich.
        // It seems from the kpsewhich manual page that it is safe to use
        // kpsewhich without --format: "When the --format option is not
        // given, the search path used when looking for a file is inferred
@@ -1185,491 +1116,84 @@ FileName const findtexfile(string const & fil, string const & /*format*/)
 
        cmd_ret const c = runCommand(kpsecmd);
 
-       LYXERR(Debug::LATEX) << "kpse status = " << c.first << '\n'
-                << "kpse result = `" << rtrim(c.second, "\n\r")
-                << '\'' << endl;
+       LYXERR(Debug::LATEX, "kpse status = " << c.first << '\n'
+                << "kpse result = `" << rtrim(c.second, "\n\r") << '\'');
        if (c.first != -1)
-               return FileName(os::internal_path(rtrim(to_utf8(from_filesystem8bit(c.second)),
-                                                       "\n\r")));
+               return FileName(rtrim(to_utf8(from_filesystem8bit(c.second)), "\n\r"));
        else
                return FileName();
 }
 
 
-void removeAutosaveFile(string const & filename)
-{
-       string a = onlyPath(filename);
-       a += '#';
-       a += onlyFilename(filename);
-       a += '#';
-       FileName const autosave(a);
-       if (fs::exists(autosave.toFilesystemEncoding()))
-               unlink(autosave);
-}
-
-
-void readBB_lyxerrMessage(FileName const & file, bool & zipped,
-       string const & message)
-{
-       LYXERR(Debug::GRAPHICS) << "[readBB_from_PSFile] "
-               << message << std::endl;
-       // FIXME: Why is this func deleting a file? (Lgb)
-       if (zipped)
-               unlink(file);
-}
-
-
-string const readBB_from_PSFile(FileName const & file)
-{
-       // in a (e)ps-file it's an entry like %%BoundingBox:23 45 321 345
-       // It seems that every command in the header has an own line,
-       // getline() should work for all files.
-       // On the other hand some plot programs write the bb at the
-       // end of the file. Than we have in the header:
-       // %%BoundingBox: (atend)
-       // In this case we must check the end.
-       bool zipped = zippedFile(file);
-       FileName const file_ = zipped ? unzipFile(file) : file;
-       string const format = getFormatFromContents(file_);
-
-       if (format != "eps" && format != "ps") {
-               readBB_lyxerrMessage(file_, zipped,"no(e)ps-format");
-               return string();
-       }
-
-       static boost::regex bbox_re(
-               "^%%BoundingBox:\\s*([[:digit:]]+)\\s+([[:digit:]]+)\\s+([[:digit:]]+)\\s+([[:digit:]]+)");
-       std::ifstream is(file_.toFilesystemEncoding().c_str());
-       while (is) {
-               string s;
-               getline(is,s);
-               boost::smatch what;
-               if (regex_match(s, what, bbox_re)) {
-                       // Our callers expect the tokens in the string
-                       // separated by single spaces.
-                       // FIXME: change return type from string to something
-                       // sensible
-                       ostringstream os;
-                       os << what.str(1) << ' ' << what.str(2) << ' '
-                          << what.str(3) << ' ' << what.str(4);
-                       string const bb = os.str();
-                       readBB_lyxerrMessage(file_, zipped, bb);
-                       return bb;
-               }
-       }
-       readBB_lyxerrMessage(file_, zipped, "no bb found");
-       return string();
-}
-
-
-int compare_timestamps(FileName const & filename1, FileName const & filename2)
+int compare_timestamps(FileName const & file1, FileName const & file2)
 {
        // If the original is newer than the copy, then copy the original
        // to the new directory.
 
-       string const file1 = filename1.toFilesystemEncoding();
-       string const file2 = filename2.toFilesystemEncoding();
        int cmp = 0;
-       if (fs::exists(file1) && fs::exists(file2)) {
-               double const tmp = difftime(fs::last_write_time(file1),
-                                           fs::last_write_time(file2));
+       if (file1.exists() && file2.exists()) {
+               double const tmp = difftime(file1.lastModified(), file2.lastModified());
                if (tmp != 0)
                        cmp = tmp > 0 ? 1 : -1;
 
-       } else if (fs::exists(file1)) {
+       } else if (file1.exists()) {
                cmp = 1;
-       } else if (fs::exists(file2)) {
+       } else if (file2.exists()) {
                cmp = -1;
        }
 
        return cmp;
 }
 
-// the following is adapted from zlib-1.2.3/contrib/minizip.c
-// and miniunz.c, except that
-// 1. mkdir, makedir is replaced by lyx' own version
-// 2. printf is replaced by lyxerr
 
-#ifdef WIN32
-uLong filetime(const char * f, tm_zip * tmzip, uLong * dt)
+bool prefs2prefs(FileName const & filename, FileName const & tempfile, bool lfuns)
 {
-       int ret = 0;
-       {
-               FILETIME ftLocal;
-               HANDLE hFind;
-               WIN32_FIND_DATA  ff32;
-
-               hFind = FindFirstFile(f,&ff32);
-               if (hFind != INVALID_HANDLE_VALUE)
-               {
-                       FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
-                       FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
-                       FindClose(hFind);
-                       ret = 1;
-               }
-       }
-       return ret;
-}
-
-#else
-#ifdef unix
-uLong filetime(const char * f, tm_zip * tmzip, uLong * /*dt*/)
-{
-       int ret=0;
-       struct stat s;                                                            /* results of stat() */
-       struct tm* filedate;
-       time_t tm_t=0;
-
-       if (strcmp(f,"-")!=0) {
-               char name[MAXFILENAME+1];
-               int len = strlen(f);
-               if (len > MAXFILENAME)
-                       len = MAXFILENAME;
-
-               strncpy(name, f,MAXFILENAME-1);
-               /* strncpy doesnt append the trailing NULL, of the string is too long. */
-               name[ MAXFILENAME ] = '\0';
-
-               if (name[len - 1] == '/')
-                       name[len - 1] = '\0';
-               /* not all systems allow stat'ing a file with / appended */
-               if (stat(name,&s)==0) {
-                       tm_t = s.st_mtime;
-                       ret = 1;
-               }
-       }
-       filedate = localtime(&tm_t);
-
-       tmzip->tm_sec  = filedate->tm_sec;
-       tmzip->tm_min  = filedate->tm_min;
-       tmzip->tm_hour = filedate->tm_hour;
-       tmzip->tm_mday = filedate->tm_mday;
-       tmzip->tm_mon  = filedate->tm_mon ;
-       tmzip->tm_year = filedate->tm_year;
-
-       return ret;
-}
-
-#else
-
-uLong filetime(const char * f, tm_zip * tmzip, uLong * dt)
-{
-       return 0;
-}
-#endif
-#endif
-
-bool zipFiles(DocFileName const & zipfile, vector<pair<string, string> > const & files)
-{
-       int err = 0;
-       zipFile zf;
-       int errclose;
-       void * buf = NULL;
-
-       int size_buf = WRITEBUFFERSIZE;
-       buf = (void*)malloc(size_buf);
-       if (buf==NULL) {
-               lyxerr << "Error allocating memory" << endl;
-               return false;
-       }
-       string const zfile = zipfile.toFilesystemEncoding();
-       const char * fname = zfile.c_str();
-
-#ifdef USEWIN32IOAPI
-       zlib_filefunc_def ffunc;
-       fill_win32_filefunc(&ffunc);
-       // false: not append
-       zf = zipOpen2(fname, false, NULL, &ffunc);
-#else
-       zf = zipOpen(fname, false);
-#endif
-
-       if (zf == NULL) {
-               lyxerr << "error opening " << zipfile << endl;
+       FileName const script = libFileSearch("scripts", "prefs2prefs.py");
+       if (script.empty()) {
+               LYXERR0("Could not find bind file conversion "
+                               "script prefs2prefs.py.");
                return false;
        }
 
-       for (vector<pair<string, string> >::const_iterator it = files.begin(); it != files.end(); ++it) {
-               FILE * fin;
-               int size_read;
-               zip_fileinfo zi;
-               const char * diskfilename = it->first.c_str();
-               const char * filenameinzip = it->second.c_str();
-               unsigned long crcFile=0;
-
-               zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
-                       zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
-               zi.dosDate = 0;
-               zi.internal_fa = 0;
-               zi.external_fa = 0;
-               filetime(filenameinzip, &zi.tmz_date, &zi.dosDate);
-
-               err = zipOpenNewFileInZip3(zf, filenameinzip, &zi,
-                       NULL,0,NULL,0,NULL /* comment*/,
-                       Z_DEFLATED,
-                       Z_DEFAULT_COMPRESSION,            // compression level
-                       0,
-               /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
-                       -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
-                       NULL,                                             // password,
-                       crcFile);
-
-               if (err != ZIP_OK) {
-                       lyxerr << "error in opening " << filenameinzip << " in zipfile" << endl;
-                       return false;
-               }
-               fin = fopen(diskfilename, "rb");
-               if (fin==NULL) {
-                       lyxerr << "error in opening " << diskfilename << " for reading" << endl;
-                       return false;
-               }
-
-               do {
-                       err = ZIP_OK;
-                       size_read = (int)fread(buf, 1, size_buf, fin);
-                       if (size_read < size_buf)
-                               if (feof(fin)==0) {
-                                       lyxerr << "error in reading " << filenameinzip << endl;
-                                       return false;
-                               }
-
-                       if (size_read>0) {
-                               err = zipWriteInFileInZip (zf, buf, size_read);
-                               if (err<0) {
-                                       lyxerr << "error in writing " << filenameinzip << " in the zipfile" << endl;
-                                       return false;
-                               }
-                       }
-               } while ((err == ZIP_OK) && (size_read>0));
+       ostringstream command;
+       command << os::python() << ' ' << quoteName(script.toFilesystemEncoding())
+         << ' ' << (lfuns ? "-l" : "-p") << ' '
+               << quoteName(filename.toFilesystemEncoding())
+               << ' ' << quoteName(tempfile.toFilesystemEncoding());
+       string const command_str = command.str();
 
-               if (fin)
-                       fclose(fin);
+       LYXERR(Debug::FILES, "Running `" << command_str << '\'');
 
-               err = zipCloseFileInZip(zf);
-               if (err != ZIP_OK) {
-                       lyxerr << "error in closing " << filenameinzip << "in the zipfile" << endl;
-                       return false;
-               }
-       }
-       errclose = zipClose(zf, NULL);
-       if (errclose != ZIP_OK) {
-               lyxerr << "error in closing " << zipfile << endl;
+       cmd_ret const ret = runCommand(command_str);
+       if (ret.first != 0) {
+               LYXERR0("Could not run file conversion script prefs2prefs.py.");
                return false;
        }
-       free(buf);
        return true;
 }
 
-// adapted from miniunz.c
-
-/* change_file_date : change the date/time of a file
-       filename : the filename of the file where date/time must be modified
-       dosdate : the new date at the MSDos format (4 bytes)
-       tmu_date : the SAME new date at the tm_unz format */
-void change_file_date(const char * filename, uLong dosdate, tm_unz tmu_date)
+int fileLock(const char * lock_file)
 {
-#ifdef WIN32
-       HANDLE hFile;
-       FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
-
-       hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE,
-               0,NULL,OPEN_EXISTING,0,NULL);
-       GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
-       DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
-       LocalFileTimeToFileTime(&ftLocal,&ftm);
-       SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
-       CloseHandle(hFile);
-#else
-#ifdef unix
-       utimbuf ut;
-       tm newdate;
-
-       newdate.tm_sec = tmu_date.tm_sec;
-       newdate.tm_min=tmu_date.tm_min;
-       newdate.tm_hour=tmu_date.tm_hour;
-       newdate.tm_mday=tmu_date.tm_mday;
-       newdate.tm_mon=tmu_date.tm_mon;
-       if (tmu_date.tm_year > 1900)
-               newdate.tm_year=tmu_date.tm_year - 1900;
-       else
-               newdate.tm_year=tmu_date.tm_year ;
-       newdate.tm_isdst=-1;
-
-       ut.actime=ut.modtime=mktime(&newdate);
-       utime(filename,&ut);
-#endif
+       int fd = -1;
+#if defined(HAVE_LOCKF)
+       fd = open(lock_file, O_CREAT|O_APPEND|O_SYNC|O_RDWR, 0666);
+       if (lockf(fd, F_LOCK, 0) != 0) {
+               close(fd);
+               return(-1);
+       }
 #endif
+       return(fd);
 }
 
-
-int do_extract_currentfile(unzFile uf,
-       const int * popt_extract_without_path,
-       int * popt_overwrite,
-       const char * password,
-       const char * dirname)
+void fileUnlock(int fd, const char * /* lock_file*/)
 {
-       char filename_inzip[256];
-       char* filename_withoutpath;
-       char* p;
-       int err=UNZ_OK;
-       FILE *fout=NULL;
-       void* buf;
-       uInt size_buf;
-
-       unz_file_info file_info;
-       //uLong ratio=0;
-       err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
-
-       if (err!=UNZ_OK) {
-               lyxerr << "error " << err << " with zipfile in unzGetCurrentFileInfo" << endl;
-               return err;
-       }
-
-       size_buf = WRITEBUFFERSIZE;
-       buf = (void*)malloc(size_buf);
-       if (buf==NULL) {
-               lyxerr << "Error allocating memory" << endl;
-               return UNZ_INTERNALERROR;
+#if defined(HAVE_LOCKF)
+       if (fd >= 0) {
+               if (lockf(fd, F_ULOCK, 0))
+                       LYXERR0("Can't unlock the file.");
+               close(fd);
        }
-
-       p = filename_withoutpath = filename_inzip;
-       while ((*p) != '\0') {
-               if (((*p)=='/') || ((*p)=='\\'))
-                       filename_withoutpath = p+1;
-               p++;
-       }
-       // this is a directory
-       if ((*filename_withoutpath)=='\0') {
-               if ((*popt_extract_without_path)==0)
-                       makedir(filename_inzip);
-       }
-       // this is a filename
-       else {
-               char write_filename[1024];
-
-               strcpy(write_filename, dirname);
-               int len = strlen(write_filename);
-               if (write_filename[len-1] != '\\' &&
-                       write_filename[len-1] != '/')
-                       strcat(write_filename, "/");
-
-               if ((*popt_extract_without_path)==0)
-                       strcat(write_filename, filename_inzip);
-               else
-                       strcat(write_filename, filename_withoutpath);
-
-               err = unzOpenCurrentFilePassword(uf,password);
-               if (err!=UNZ_OK) {
-                       lyxerr << "error " << err << " with zipfile in unzOpenCurrentFilePassword" << endl;
-               } else {
-                       fout=fopen(write_filename, "wb");
-
-                       /* some zipfile don't contain directory alone before file */
-                       if ((fout==NULL) && ((*popt_extract_without_path)==0) &&
-                               (filename_withoutpath!=(char*)filename_inzip)) {
-                               char c=*(filename_withoutpath-1);
-                               *(filename_withoutpath-1)='\0';
-                               makedir(write_filename);
-                               *(filename_withoutpath-1)=c;
-                               fout=fopen(write_filename,"wb");
-                       }
-
-                       if (fout==NULL) {
-                               lyxerr << "error opening " << write_filename << endl;
-                       }
-               }
-
-               if (fout!=NULL) {
-                       LYXERR(Debug::FILES) << " extracting: " << write_filename << endl;
-
-                       do {
-                               err = unzReadCurrentFile(uf,buf,size_buf);
-                               if (err<0) {
-                                       lyxerr << "error " << err << " with zipfile in unzReadCurrentFile" << endl;
-                                       break;
-                               }
-                               if (err>0)
-                                       if (fwrite(buf,err,1,fout)!=1) {
-                                               lyxerr << "error in writing extracted file" << endl;
-                                               err=UNZ_ERRNO;
-                                               break;
-                                       }
-                       } while (err>0);
-                       if (fout)
-                               fclose(fout);
-
-                       if (err==0)
-                               change_file_date(write_filename,file_info.dosDate,
-                                       file_info.tmu_date);
-               }
-
-               if (err==UNZ_OK) {
-                       err = unzCloseCurrentFile (uf);
-                       if (err!=UNZ_OK) {
-                               lyxerr << "error " << err << " with zipfile in unzCloseCurrentFile" << endl;
-                       }
-               }
-               else
-                       unzCloseCurrentFile(uf);          /* don't lose the error */
-       }
-
-       free(buf);
-       return err;
-}
-
-
-bool unzipToDir(string const & zipfile, string const & dirname)
-{
-       unzFile uf=NULL;
-#ifdef USEWIN32IOAPI
-       zlib_filefunc_def ffunc;
-#endif
-
-       const char * zipfilename = zipfile.c_str();
-
-#ifdef USEWIN32IOAPI
-       fill_win32_filefunc(&ffunc);
-       uf = unzOpen2(zipfilename, &ffunc);
-#else
-       uf = unzOpen(zipfilename);
 #endif
-
-       if (uf==NULL) {
-               lyxerr << "Cannot open " << zipfile << " or " << zipfile << ".zip" << endl;
-               return false;
-       }
-
-       uLong i;
-       unz_global_info gi;
-       int err;
-       //FILE* fout=NULL;
-       int opt_extract_without_path = 0;
-       int opt_overwrite = 1;
-       char * password = NULL;
-
-       err = unzGetGlobalInfo (uf, &gi);
-       if (err != UNZ_OK) {
-               lyxerr << "error " << err << " with zipfile in unzGetGlobalInfo " << endl;
-               return false;
-       }
-
-       for (i=0; i < gi.number_entry; i++) {
-               if (do_extract_currentfile(uf, &opt_extract_without_path,
-                       &opt_overwrite,
-                       password, dirname.c_str()) != UNZ_OK)
-                       break;
-
-               if ((i+1)<gi.number_entry) {
-                       err = unzGoToNextFile(uf);
-                       if (err != UNZ_OK) {
-                               lyxerr << "error " << err << " with zipfile in unzGoToNextFile" << endl;;
-                               break;
-                       }
-               }
-       }
-
-       unzCloseCurrentFile(uf);
-    return true;
 }
 
 } //namespace support