]> 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 19d970146490d92e9e51b64f842764522156dd49..040272aade620e406bed47dcca8947126c0c763d 100644 (file)
 #include "support/qstring_helpers.h"
 
 #include <QDir>
+#include <QTemporaryFile>
 
 #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>
@@ -90,6 +97,60 @@ bool isValidDVIFileName(string const & filename)
 }
 
 
+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;
+}
+
+
 string const latex_path(string const & original_path,
                latex_path_extension extension,
                latex_path_dots dots)
@@ -178,6 +239,8 @@ string const quoteName(string const & name, quote_style style)
                // 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, "\\", "\\\\"), "\"", "\\\"")
                     + "\"";
@@ -242,8 +305,14 @@ FileName const fileSearch(string const & path, string const & name,
                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)
+       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();
@@ -255,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);
+                                    name, ext, mode);
        if (!fullname.empty())
                return fullname;
 
        if (!package().build_support().empty())
                fullname = fileSearch(addPath(package().build_support().absFileName(), dir),
-                                     name, ext);
+                                     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);
 }
 
 
@@ -323,17 +393,17 @@ FileName const i18nLibFileSearch(string const & dir, string const & name,
 
 
 FileName const imageLibFileSearch(string & dir, string const & name,
-                 string const & ext)
+                 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);
+               FileName const fn = libFileSearch(imagedir, name, ext, mode);
                if (fn.exists()) {
                        dir = imagedir;
                        return fn;
                }
        }
-       return libFileSearch(dir, name, ext);
+       return libFileSearch(dir, name, ext, mode);
 }
 
 
@@ -378,12 +448,35 @@ string const commandPrep(string const & command_in)
 }
 
 
+static string createTempFile(QString const & mask)
+{
+       // 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;
+       }
+       LYXERR(Debug::FILES, "Unable to create temporary file with following template: "
+                       << qt_tmp.fileTemplate());
+       return string();
+}
+
+
 static FileName createTmpDir(FileName const & tempdir, string const & mask)
 {
        LYXERR(Debug::FILES, "createTmpDir: tempdir=`" << tempdir << "'\n"
                << "createTmpDir:    mask=`" << mask << '\'');
 
-       FileName const tmpfl = FileName::tempName(tempdir, mask);
+       QFileInfo tmp_fi(QDir(toqstr(tempdir.absFileName())), toqstr(mask));
+       FileName const tmpfl(createTempFile(tmp_fi.absoluteFilePath()));
 
        if (tmpfl.empty() || !tmpfl.createDirectory(0700)) {
                LYXERR0("LyX could not create temporary directory in " << tempdir
@@ -613,8 +706,15 @@ string latexEnvCmdPrefix(string const & path)
                return "env TEXINPUTS=\"." + sep + texinputs_prefix
                                          + sep + texinputs + "\" ";
        else
-               return "cmd /d /c set TEXINPUTS=." + sep + texinputs_prefix
-                                                  + sep + texinputs + "&";
+#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
 }
 
 
@@ -840,7 +940,7 @@ bool readLink(FileName const & file, FileName & link)
        string const encoded = file.toFilesystemEncoding();
 #ifdef HAVE_DEF_PATH_MAX
        char linkbuffer[PATH_MAX + 1];
-       int const nRead = ::readlink(encoded.c_str(),
+       ssize_t const nRead = ::readlink(encoded.c_str(),
                                     linkbuffer, sizeof(linkbuffer) - 1);
        if (nRead <= 0)
                return false;
@@ -854,7 +954,7 @@ bool readLink(FileName const & file, FileName & link)
                if (nRead < 0) {
                        return false;
                }
-               if (nRead < buf.size() - 1) {
+               if (static_cast<size_t>(nRead) < buf.size() - 1) {
                        break;
                }
                buf.resize(buf.size() * 2);