commit c8015878e1375f83574a8497faadd7e8c6aa8859
Author: Jean-Marc Lasgouttes <lasgout...@lyx.org>
Date:   Fri Oct 28 17:21:33 2022 +0200

    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.
---
 src/support/Systemcall.cpp      |  112 ++++++++++++++++++---------------------
 src/support/SystemcallPrivate.h |    2 +-
 src/support/filetools.cpp       |   60 ++++++++++++---------
 src/support/filetools.h         |   14 ++++-
 4 files changed, 99 insertions(+), 89 deletions(-)

diff --git a/src/support/Systemcall.cpp b/src/support/Systemcall.cpp
index d339e11..5262da7 100644
--- a/src/support/Systemcall.cpp
+++ b/src/support/Systemcall.cpp
@@ -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,
-                     string & errfile)
+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
        }
 }
 
diff --git a/src/support/SystemcallPrivate.h b/src/support/SystemcallPrivate.h
index 19771df..f9b27c3 100644
--- a/src/support/SystemcallPrivate.h
+++ b/src/support/SystemcallPrivate.h
@@ -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();
diff --git a/src/support/filetools.cpp b/src/support/filetools.cpp
index d554f47..1bff014 100644
--- a/src/support/filetools.cpp
+++ b/src/support/filetools.cpp
@@ -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 + "\" & ";
+       // NOTE: the dummy blank dirs are necessary to force the
+       //       QProcess parser to quote the argument (see bug 9453)
+       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;
 }
 
 
diff --git a/src/support/filetools.h b/src/support/filetools.h
index 404dec2..a4ee8e3 100644
--- a/src/support/filetools.h
+++ b/src/support/filetools.h
@@ -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.
-- 
lyx-cvs mailing list
lyx-cvs@lists.lyx.org
http://lists.lyx.org/mailman/listinfo/lyx-cvs

Reply via email to