mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 21:21:32 +00:00
WIP: refactor Systemcall
**WARNING; only compilation has been ested; even that does not work** The goal of this commit is to use the list-based API to QProcess::start, to avoid annoying syntax issues (see issues with pasting from LaTeX). * Create a new latexEnvironment() in filetools.h that returns a map<string, string> containing the variables and their values. * Rewrite parsecmd() so that it returns a QStringList of tokenized parameters. * Use this in startProcess. This is the part is is not finished yet. Obviously, this will not be possible to get right for 2.4.0.
This commit is contained in:
parent
22e5903bf3
commit
c8015878e1
@ -13,13 +13,14 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "support/Systemcall.h"
|
||||
#include "support/SystemcallPrivate.h"
|
||||
|
||||
#include "support/debug.h"
|
||||
#include "support/filetools.h"
|
||||
#include "support/gettext.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/qstring_helpers.h"
|
||||
#include "support/Systemcall.h"
|
||||
#include "support/SystemcallPrivate.h"
|
||||
#include "support/os.h"
|
||||
#include "support/ProgressInterface.h"
|
||||
|
||||
@ -163,19 +164,20 @@ namespace {
|
||||
* "\a" -> "\a"
|
||||
* "a\"b" -> "a"""b"
|
||||
*/
|
||||
string const parsecmd(string const & incmd, string & infile, string & outfile,
|
||||
QStringList const parsecmd(string const & incmd, string & infile, string & outfile,
|
||||
string & errfile)
|
||||
{
|
||||
bool in_single_quote = false;
|
||||
bool in_double_quote = false;
|
||||
bool escaped = false;
|
||||
string const python_call = os::python();
|
||||
QStringList arguments;
|
||||
vector<string> outcmd(4);
|
||||
size_t start = 0;
|
||||
|
||||
if (prefixIs(incmd, python_call)) {
|
||||
outcmd[0] = os::python();
|
||||
start = python_call.length();
|
||||
if (prefixIs(incmd, python_call + ' ')) {
|
||||
arguments << QString::fromLocal8Bit(trim(os::python()).c_str());
|
||||
start = python_call.length() + 1;
|
||||
}
|
||||
|
||||
for (size_t i = start, o = 0; i < incmd.length(); ++i) {
|
||||
@ -194,30 +196,12 @@ string const parsecmd(string const & incmd, string & infile, string & outfile,
|
||||
outcmd[o] += c;
|
||||
continue;
|
||||
}
|
||||
if (c == '"') {
|
||||
if (escaped) {
|
||||
// Don't triple double-quotes for redirection
|
||||
// files as these won't be parsed by QProcess
|
||||
outcmd[o] += string(o ? "\"" : "\"\"\"");
|
||||
escaped = false;
|
||||
} else {
|
||||
outcmd[o] += c;
|
||||
in_double_quote = !in_double_quote;
|
||||
}
|
||||
} else if (c == '\\' && !escaped) {
|
||||
escaped = true;
|
||||
} else if (c == '>' && !(in_double_quote || escaped)) {
|
||||
if (suffixIs(outcmd[o], " 2")) {
|
||||
outcmd[o] = rtrim(outcmd[o], "2");
|
||||
o = 2;
|
||||
} else {
|
||||
if (suffixIs(outcmd[o], " 1"))
|
||||
outcmd[o] = rtrim(outcmd[o], "1");
|
||||
o = 1;
|
||||
}
|
||||
} else if (c == '<' && !(in_double_quote || escaped)) {
|
||||
o = 3;
|
||||
if (c == ' ' && !(in_double_quote || escaped)) {
|
||||
if (o == 0)
|
||||
arguments << QString::fromLocal8Bit(trim(outcmd[o]).c_str());
|
||||
o = 0;
|
||||
#if defined (USE_MACOSX_PACKAGING)
|
||||
// FIXME!!!!
|
||||
} else if (o == 0 && i > 4 && c == ' ' && !(in_double_quote || escaped)) {
|
||||
// if a macOS app is detected with an additional argument
|
||||
// use open command as prefix to get it work
|
||||
@ -232,6 +216,28 @@ string const parsecmd(string const & incmd, string & infile, string & outfile,
|
||||
}
|
||||
outcmd[o] += c;
|
||||
#endif
|
||||
} else if (c == '"') {
|
||||
if (escaped) {
|
||||
outcmd[o] += c;
|
||||
escaped = false;
|
||||
} else
|
||||
in_double_quote = !in_double_quote;
|
||||
} else if (c == '\\' && !escaped) {
|
||||
escaped = true;
|
||||
} else if (c == '>' && o == 0 && !(in_double_quote || escaped)) {
|
||||
if (outcmd[o] == "2") {
|
||||
outcmd[o].clear();
|
||||
o = 2;
|
||||
outcmd[o].clear();
|
||||
} else if (outcmd[o] == "1" || outcmd[o].empty()) {
|
||||
outcmd[o].clear();
|
||||
o = 1;
|
||||
outcmd[o].clear();
|
||||
}
|
||||
} else if (c == '<' && o == 0 && outcmd[o].empty() && !(in_double_quote || escaped)) {
|
||||
outcmd[o].clear();
|
||||
o = 3;
|
||||
outcmd[o].clear();
|
||||
} else {
|
||||
if (escaped && in_double_quote)
|
||||
outcmd[o] += '\\';
|
||||
@ -242,7 +248,7 @@ string const parsecmd(string const & incmd, string & infile, string & outfile,
|
||||
infile = trim(outcmd[3], " \"");
|
||||
outfile = trim(outcmd[1], " \"");
|
||||
errfile = trim(outcmd[2], " \"");
|
||||
return trim(outcmd[0]);
|
||||
return arguments;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -267,8 +273,7 @@ int Systemcall::startscript(Starttype how, string const & what,
|
||||
string infile;
|
||||
string outfile;
|
||||
string errfile;
|
||||
QString const cmd = QString::fromLocal8Bit(
|
||||
parsecmd(what_ss, infile, outfile, errfile).c_str());
|
||||
QStringList const cmd = parsecmd(what_ss, infile, outfile, errfile);
|
||||
|
||||
SystemcallPrivate d(infile, outfile, errfile);
|
||||
bool do_events = process_events || how == WaitLoop;
|
||||
@ -379,27 +384,21 @@ SystemcallPrivate::SystemcallPrivate(std::string const & sf, std::string const &
|
||||
}
|
||||
|
||||
|
||||
void SystemcallPrivate::startProcess(QString const & cmd, string const & path,
|
||||
void SystemcallPrivate::startProcess(string const & cmd, string const & path,
|
||||
string const & lpath, bool detached)
|
||||
{
|
||||
cmd_ = cmd;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
// FIXME pass command and arguments separated in the first place
|
||||
/* The versions of startDetached() and start() that accept a
|
||||
* QStringList object exist since Qt4, but it is only in Qt 5.15
|
||||
* that splitCommand() was introduced and the plain versions of
|
||||
* start/startDetached() have been deprecated.
|
||||
* The cleanest solution would be to have parsecmd() produce a
|
||||
* QStringList for arguments, instead of transforming the string
|
||||
* into something that the QProcess splitter accepts.
|
||||
*/
|
||||
QStringList arguments = QProcess::splitCommand(toqstr(latexEnvCmdPrefix(path, lpath)) + cmd_);
|
||||
QString command = (arguments.empty()) ? QString() : arguments.first();
|
||||
if (arguments.size() == 1)
|
||||
arguments.clear();
|
||||
else if (!arguments.empty())
|
||||
arguments.removeFirst();
|
||||
#endif
|
||||
cmd_ = toqstr(cmd);
|
||||
|
||||
// Set the environment for LaTeX
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
for (auto const & v : latexEnvironment(path, lpath))
|
||||
latexenv.insert(toqstr(v.first), QString::fromLocal8Bit(v.second.c_str()));
|
||||
process_->setProcessEnvironment(env);
|
||||
|
||||
// Parse the command line
|
||||
QStringList arguments = parsecmd(cmd);
|
||||
QString command = arguments.empty() ? QString() : arguments.takeFirst();
|
||||
|
||||
if (detached) {
|
||||
state = SystemcallPrivate::Running;
|
||||
#ifdef Q_OS_WIN32
|
||||
@ -411,11 +410,8 @@ void SystemcallPrivate::startProcess(QString const & cmd, string const & path,
|
||||
if (err_file_.empty())
|
||||
process_->setStandardErrorFile(QProcess::nullDevice());
|
||||
#endif
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
|
||||
if (!QProcess::startDetached(command, arguments)) {
|
||||
#else
|
||||
if (!QProcess::startDetached(toqstr(latexEnvCmdPrefix(path, lpath)) + cmd_)) {
|
||||
#endif
|
||||
state = SystemcallPrivate::Error;
|
||||
return;
|
||||
}
|
||||
@ -423,11 +419,7 @@ void SystemcallPrivate::startProcess(QString const & cmd, string const & path,
|
||||
delete released;
|
||||
} else if (process_) {
|
||||
state = SystemcallPrivate::Starting;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
process_->start(command, arguments);
|
||||
#else
|
||||
process_->start(toqstr(latexEnvCmdPrefix(path, lpath)) + cmd_);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
State state;
|
||||
|
||||
bool waitWhile(State, bool processEvents, int timeout = -1);
|
||||
void startProcess(QString const & cmd, std::string const & path,
|
||||
void startProcess(std::string const & cmd, std::string const & path,
|
||||
std::string const & lpath, bool detach);
|
||||
|
||||
int exitCode();
|
||||
|
@ -737,12 +737,13 @@ string const replaceEnvironmentPath(string const & path)
|
||||
|
||||
|
||||
// Return a command prefix for setting the environment of the TeX engine.
|
||||
string latexEnvCmdPrefix(string const & path, string const & lpath)
|
||||
map <string,string> latexEnvironment(string const & path, string const & lpath)
|
||||
{
|
||||
map<string, string> env;
|
||||
bool use_lpath = !(lpath.empty() || lpath == "." || lpath == "./");
|
||||
|
||||
if (path.empty() || (lyxrc.texinputs_prefix.empty() && !use_lpath))
|
||||
return string();
|
||||
return env;
|
||||
|
||||
string texinputs_prefix = lyxrc.texinputs_prefix.empty() ? string()
|
||||
: os::latex_path_list(
|
||||
@ -766,30 +767,37 @@ string latexEnvCmdPrefix(string const & path, string const & lpath)
|
||||
texinputs_prefix.append(sep + abslpath);
|
||||
}
|
||||
|
||||
if (os::shell() == os::UNIX)
|
||||
return "env TEXINPUTS=\"." + sep + texinputs_prefix
|
||||
+ sep + texinputs + "\" "
|
||||
+ "BIBINPUTS=\"." + sep + allother_prefix
|
||||
+ sep + bibinputs + "\" "
|
||||
+ "BSTINPUTS=\"." + sep + allother_prefix
|
||||
+ sep + bstinputs + "\" "
|
||||
+ "TEXFONTS=\"." + sep + allother_prefix
|
||||
+ sep + texfonts + "\" ";
|
||||
else
|
||||
// NOTE: the dummy blank dirs are necessary to force the
|
||||
// QProcess parser to quote the argument (see bug 9453)
|
||||
return "cmd /d /c set \"TEXINPUTS=." + sep + " "
|
||||
+ sep + texinputs_prefix
|
||||
+ sep + texinputs + "\" & "
|
||||
+ "set \"BIBINPUTS=." + sep + " "
|
||||
+ sep + allother_prefix
|
||||
+ sep + bibinputs + "\" & "
|
||||
+ "set \"BSTINPUTS=." + sep + " "
|
||||
+ sep + allother_prefix
|
||||
+ sep + bstinputs + "\" & "
|
||||
+ "set \"TEXFONTS=." + sep + " "
|
||||
+ sep + allother_prefix
|
||||
+ sep + texfonts + "\" & ";
|
||||
string const dummy = (os::shell() == os::UNIX) ? string() : (" " + sep);
|
||||
|
||||
env.insert({ "TEXINPUTS", "." + sep + dummy + texinputs_prefix + sep + texinputs });
|
||||
env.insert({ "BIBINPUTS", "." + sep + dummy + allother_prefix + sep + bibinputs });
|
||||
env.insert({ "BSTINPUTS", "." + sep + dummy + allother_prefix + sep + bstinputs });
|
||||
env.insert({ "TEXFONTS", "." + sep + dummy + allother_prefix + sep + texfonts });
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
|
||||
// Return a command prefix for setting the environment of the TeX engine.
|
||||
string latexEnvCmdPrefix(string const & path, string const & lpath)
|
||||
{
|
||||
auto const env = latexEnvironment(path, lpath);
|
||||
if (env.empty())
|
||||
return string();
|
||||
|
||||
string prefix;
|
||||
if (os::shell() == os::UNIX) {
|
||||
prefix = "env ";
|
||||
for (auto const & v : latexEnvironment(path, lpath))
|
||||
prefix += v.first + "=" + v.second + " ";
|
||||
} else {
|
||||
prefix = "cmd /d /c ";
|
||||
for (auto const & v : latexEnvironment(path, lpath))
|
||||
prefix += "set \"" + v.first + "=" + v.second + "\" & ";
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,9 +14,10 @@
|
||||
|
||||
#include "support/docstring.h"
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace lyx {
|
||||
namespace support {
|
||||
@ -289,6 +290,15 @@ std::string const onlyFileName(std::string const & fname);
|
||||
*/
|
||||
std::string const replaceEnvironmentPath(std::string const & path);
|
||||
|
||||
|
||||
/**
|
||||
Return a map to be used to set the environment of the TeX engine
|
||||
with respect to the paths \p path and \p lpath.
|
||||
*/
|
||||
std::map <std::string, std::string>
|
||||
latexEnvironment(std::string const & path, std::string const & lpath);
|
||||
|
||||
|
||||
/**
|
||||
Return a string to be used as a prefix to a command for setting the
|
||||
environment of the TeX engine with respect to the paths \p path and \p lpath.
|
||||
|
Loading…
Reference in New Issue
Block a user