]> git.lyx.org Git - lyx.git/blob - src/support/os.cpp
Fix functions that used functions but did not defined it
[lyx.git] / src / support / os.cpp
1 /**
2  * \file os.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Ruurd A. Reitsma
7  * \author Enrico Forestieri
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #ifdef _WIN32
15 # define _WIN32_WINNT 0x0600
16 #endif
17
18 #include "support/convert.h"
19 #include "support/debug.h"
20 #include "support/filetools.h"
21 #include "support/qstring_helpers.h"
22
23 #include <QDir>
24
25 #include <regex>
26
27 #if defined(__CYGWIN__)
28 #include "support/os_cygwin.cpp"
29 #elif defined(_WIN32)
30 #include "support/os_win32.cpp"
31 #else
32 #include "support/os_unix.cpp"
33 #endif
34
35 // Static assert to break compilation on platforms where
36 // int/unsigned int is not 4 bytes. Added to make sure that
37 // e.g., the author hash is always 32-bit.
38 template<bool Condition> struct static_assert_helper;
39 template <> struct static_assert_helper<true> {};
40 enum {
41         dummy = sizeof(static_assert_helper<sizeof(int) == 4>)
42 };
43
44 namespace lyx {
45 namespace support {
46 namespace os {
47
48 int timeout_ms()
49 {
50         // Starting in 2.4.0, we allow the user to cancel the background
51         // process at any time with LFUN_EXPORT_CANCEL, so the timeout dialog
52         // is no longer useful.
53         // "-1" effectively disables the timeout (it is a special case in
54         // SystemcallPrivate::waitWhile()).
55         return -1;
56 }
57
58
59 static string const python_call(string const & binary, bool verbose = false)
60 {
61         const string version_info = " -c \"import sys; print(sys.version_info[:2], end='')\"";
62         // Default to "python3" if no binary is given.
63         if (binary.empty())
64                 return "python3";
65
66         if (verbose)
67                 lyxerr << "Examining " << binary << "\n";
68         // Check whether this is a python 2 or 3 binary.
69         cmd_ret const out = runCommand(binary + version_info);
70
71         smatch sm;
72         try {
73                 static regex const python_reg("\\((\\d*), (\\d*)\\)");
74                 if (!out.valid || !regex_match(out.result, sm, python_reg))
75                         return string();
76         } catch(regex_error const & /*e*/) {
77                 LYXERR0("Regex error! This should not happen.");
78                 return string();
79         }
80
81         int major = convert<int>(sm.str(1));
82         int minor = convert<int>(sm.str(2));
83         if((major < 3) || (major == 3 && minor < 8))
84                 return string();
85
86         if (verbose)
87                 lyxerr << "Found Python " << out.result << "\n";
88         return binary;
89 }
90
91
92 static string const find_python_binary()
93 {
94         // This function takes inspiration from PEP 394 and PEP 397
95         // PEP 394 -- The "python" Command on Unix-Like Systems
96         // https://www.python.org/dev/peps/pep-0394/
97         // PEP 397 -- Python launcher for Windows
98         // https://www.python.org/dev/peps/pep-0397/
99
100 #ifdef _WIN32
101         // Check through python launcher whether python 3 is
102         // installed on computer.
103         string command = python_call("py -3");
104 #else
105         // Check whether python3 in PATH is the right one.
106         string command = python_call("python3");
107 #endif // _WIN32
108         if (!command.empty())
109                 return command;
110
111         // python3 does not exists, let us try to find python3.x in PATH
112         // the search is probably broader than required
113         // but we are trying hard to find a valid python binary
114         vector<string> const path = getEnvPath("PATH");
115         lyxerr << "Looking for python 3.x ...\n";
116         for (auto const & bin : path) {
117                 QString const dir = toqstr(bin);
118                 string const localdir = dir.toLocal8Bit().constData();
119                 QDir qdir(dir);
120                 qdir.setFilter(QDir::Files | QDir::Executable);
121                 QStringList list = qdir.entryList(QStringList("python3*"));
122                 for (auto const & bin2 : list) {
123                         string const binary = "\"" + addName(localdir,
124                                 bin2.toLocal8Bit().constData()) + "\"";
125                         command = python_call(binary, true);
126                         if (!command.empty())
127                                 return command;
128                 }
129         }
130
131         if (!command.empty())
132                 return command;
133
134         // If this happens all hope is lost that this is a sane system
135         lyxerr << "Warning: No Python 3.x binary found.\n";
136         return python_call("");
137 }
138
139
140 string const python(bool reset)
141 {
142         static string command = find_python_binary();
143         // FIXME THREAD
144         if (reset) {
145                 command = find_python_binary();
146         }
147         return command;
148 }
149
150
151 bool hasPython()
152 {
153         return !(python_call(python()).empty());
154 }
155
156 string const python_info()
157 {
158         const string info_version = " -c \"import sys; print('{} ({})'.format(sys.version.split()[0],sys.executable), end='')\"";
159         if (!hasPython())
160                 return("None");
161         return (runCommand(python() + info_version).result);
162 }
163
164 } // namespace os
165 } // namespace support
166 } // namespace lyx