]> git.lyx.org Git - lyx.git/blobdiff - src/support/os.cpp
Fix some warnings
[lyx.git] / src / support / os.cpp
index b1537e3655984d7d5def27a44d74d7b6e2de33a3..616b9c6936d4a16594f239fbb2dc1d2332db1358 100644 (file)
 
 #include <config.h>
 
-#include "debug.h"
-#include "filetools.h"
-#include "qstring_helpers.h"
+#ifdef _WIN32
+# define _WIN32_WINNT 0x0600
+#endif
+
+#include "support/convert.h"
+#include "support/debug.h"
+#include "support/filetools.h"
+#include "support/qstring_helpers.h"
+#include "support/regex.h"
 
 #include <QDir>
 
@@ -30,7 +36,7 @@
 // e.g., the author hash is always 32-bit.
 template<bool Condition> struct static_assert_helper;
 template <> struct static_assert_helper<true> {};
-enum { 
+enum {
        dummy = sizeof(static_assert_helper<sizeof(int) == 4>)
 };
 
@@ -38,70 +44,147 @@ namespace lyx {
 namespace support {
 namespace os {
 
-static string const python2(string const & binary, bool verbose = false)
+int timeout_min()
+{
+       return 3;
+}
+
+
+static string const python23_call(string const & binary, bool verbose = false)
 {
+       const string version_info = " -c \"from __future__ import print_function;import sys; print(sys.version_info[:2], end=\\\"\\\")\"";
+       // Default to "python" if no binary is given.
+       if (binary.empty())
+               return "python -tt";
+
        if (verbose)
                lyxerr << "Examining " << binary << "\n";
+       // Check whether this is a python 2 or 3 binary.
+       cmd_ret const out = runCommand(binary + version_info);
+
+       smatch sm;
+       try {
+               static regex const python_reg("\\((\\d*), (\\d*)\\)");
+               if (out.first < 0 || !regex_match(out.second, sm, python_reg))
+                       return string();
+       } catch(regex_error const & /*e*/) {
+               LYXERR0("Regex error! This should not happen.");
+               return string();
+       }
 
-       // Check whether this is a python 2 binary.
-       cmd_ret const out = runCommand(binary + " -V 2>&1");
-       if (out.first < 0 || !prefixIs(out.second, "Python 2"))
+       int major = convert<int>(sm.str(1));
+       int minor = convert<int>(sm.str(2));
+       if((major == 2 && minor < 7) || (major == 3 && minor < 5))
                return string();
 
        if (verbose)
-               lyxerr << "Found " << out.second << "\n";
-       return binary;
+               lyxerr << "Found Python " << out.second << "\n";
+       // Add the -tt switch so that mixed tab/whitespace
+       // indentation is an error
+       return binary + " -tt";
 }
 
 
-int timeout_min()
+static string const find_python_binary()
 {
-       return 3;
+       // This function takes inspiration from PEP 394 and PEP 397
+       // PEP 394 -- The "python" Command on Unix-Like Systems
+       // https://www.python.org/dev/peps/pep-0394/
+       // PEP 397 -- Python launcher for Windows
+       // https://www.python.org/dev/peps/pep-0397/
+
+#ifdef _WIN32
+       // Check through python launcher whether python 3 is
+       // installed on computer.
+       string command = python23_call("py -3");
+#else
+       // Check whether python3 in PATH is the right one.
+       string command = python23_call("python3");
+#endif // _WIN32
+       if (!command.empty())
+               return command;
+
+#ifndef _WIN32
+       // python3 does not exists, let us try to find python3.x in PATH
+       // the search is probably broader than required
+       // but we are trying hard to find a valid python binary
+       vector<string> const path = getEnvPath("PATH");
+       lyxerr << "Looking for python 3.x ...\n";
+       for (auto bin : path) {
+               QString const dir = toqstr(bin);
+               string const localdir = dir.toLocal8Bit().constData();
+               QDir qdir(dir);
+               qdir.setFilter(QDir::Files | QDir::Executable);
+               QStringList list = qdir.entryList(QStringList("python3*"));
+               for (auto bin2 : list) {
+                       string const binary = "\"" + addName(localdir,
+                               bin2.toLocal8Bit().constData()) + "\"";
+                       command = python23_call(binary, true);
+                       if (!command.empty())
+                               return command;
+               }
+       }
+#endif // !_WIN32
+
+       // python 3 was not found let us look for python 2
+#ifdef _WIN32
+       command = python23_call("py -2");
+#else
+       command = python23_call("python2");
+#endif // _WIN32
+       if (!command.empty())
+               return command;
+
+#ifdef _WIN32
+       // python launcher is not installed, let cmd auto check 
+       // PATH for a python.exe
+       command = python23_call("python");
+       if (!command.empty())
+               return command;
+
+       //failed, prepare to search PATH manually
+       vector<string> const path = getEnvPath("PATH");
+       lyxerr << "Manually looking for python in PATH ...\n";
+       QString const exeName = "python*";
+#else
+       // python2 does not exists, let us try to find python2.x in PATH
+       // the search is probably broader than required
+       // but we are trying hard to find a valid python binary
+       lyxerr << "Looking for python 2.x ...\n";
+       QString const exeName = "python2*";
+#endif // _WIN32
+
+       for (auto bin : path) {
+               QString const dir = toqstr(bin);
+               string const localdir = dir.toLocal8Bit().constData();
+               QDir qdir(dir);
+               qdir.setFilter(QDir::Files | QDir::Executable);
+               QStringList list = qdir.entryList(QStringList(exeName));
+               for (auto bin2 : list) {
+                       string const binary = "\"" + addName(localdir,
+                               bin2.toLocal8Bit().constData()) + "\"";
+                       command = python23_call(binary, true);
+                       if (!command.empty())
+                               return command;
+               }
+       }
+
+       // If this happens all hope is lost that this is a sane system
+       lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
+       return python23_call("");
 }
 
 
 string const python(bool reset)
 {
+       static string command = find_python_binary();
        // FIXME THREAD
-       // Check whether the first python in PATH is the right one.
-       static string command = python2("python -tt");
        if (reset) {
-               command = python2("python -tt");
-       }
-
-       if (command.empty()) {
-               // It was not, so check whether we can find it elsewhere in
-               // PATH, maybe with some suffix appended.
-               vector<string> const path = getEnvPath("PATH");
-               vector<string>::const_iterator it = path.begin();
-               vector<string>::const_iterator const end = path.end();
-               lyxerr << "Looking for python v2.x ...\n";
-               for (; it != end; ++it) {
-                       QString const dir = toqstr(*it);
-                       string const localdir = dir.toLocal8Bit().constData();
-                       QDir qdir(dir);
-                       qdir.setFilter(QDir::Files | QDir::Executable);
-                       QStringList list = qdir.entryList(QStringList("python*"));
-                       for (int i = 0; i < list.size() && command.empty(); ++i) {
-                               string const binary = addName(localdir,
-                                       list.at(i).toLocal8Bit().constData());
-                               command = python2(binary, true);
-                       }
-               }
-
-               // Default to "python" if no usable binary was found.
-               if (command.empty()) {
-                       lyxerr << "Warning: No python v2.x binary found.\n";
-                       command = "python";
-               }
-
-               // Add the -tt switch so that mixed tab/whitespace
-               // indentation is an error
-               command += " -tt";
+               command = find_python_binary();
        }
        return command;
 }
 
-}
-}
-}
+} // namespace os
+} // namespace support
+} // namespace lyx