]> git.lyx.org Git - features.git/blobdiff - src/support/ForkedCalls.cpp
Implement on screen numbering for Subequation module
[features.git] / src / support / ForkedCalls.cpp
index a583d09ac8d3c8856ee45d7f04ebaf41f69af700..b9462153e04afb1e879efc3eae4397ee4800a4b4 100644 (file)
@@ -24,6 +24,8 @@
 #include "support/bind.h"
 
 #include <cerrno>
+#include <cstring>
+#include <list>
 #include <queue>
 #include <sstream>
 #include <utility>
@@ -47,7 +49,6 @@
 using namespace std;
 
 
-
 namespace lyx {
 namespace support {
 
@@ -59,7 +60,7 @@ namespace {
 //
 /////////////////////////////////////////////////////////////////////
 
-class Murder : public boost::signals::trackable {
+class Murder {
 public:
        //
        static void killItDead(int secs, pid_t pid)
@@ -84,7 +85,8 @@ private:
        Murder(int secs, pid_t pid)
                : timeout_(1000*secs, Timeout::ONETIME), pid_(pid)
        {
-               timeout_.timeout.connect(lyx::bind(&Murder::kill, this));
+               // Connection is closed with this.
+               timeout_.timeout.connect([this](){ kill(); });
                timeout_.start();
        }
 
@@ -94,7 +96,7 @@ private:
        pid_t pid_;
 };
 
-} // namespace anon
+} // namespace
 
 
 /////////////////////////////////////////////////////////////////////
@@ -113,7 +115,7 @@ bool ForkedProcess::IAmAChild = false;
 
 void ForkedProcess::emitSignal()
 {
-       if (signal_.get()) {
+       if (signal_) {
                signal_->operator()(pid_, retval_);
        }
 }
@@ -129,7 +131,7 @@ int ForkedProcess::run(Starttype type)
                if (pid_ == 0)
                        //we also do this in fork(), too, but maybe someone will try
                        //to bypass that
-                       IAmAChild = true; 
+                       IAmAChild = true;
                return retval_;
        }
 
@@ -270,23 +272,27 @@ int ForkedProcess::waitForChild()
 //
 /////////////////////////////////////////////////////////////////////
 
+ForkedCall::ForkedCall(string const & path, string const & lpath)
+       : cmd_prefix_(to_filesystem8bit(from_utf8(latexEnvCmdPrefix(path, lpath))))
+{}
+
 
 int ForkedCall::startScript(Starttype wait, string const & what)
 {
        if (wait != Wait) {
-               retval_ = startScript(what, SignalTypePtr());
+               retval_ = startScript(what, sigPtr());
                return retval_;
        }
 
-       command_ = what;
+       command_ = commandPrep(trim(what));
        signal_.reset();
        return run(Wait);
 }
 
 
-int ForkedCall::startScript(string const & what, SignalTypePtr signal)
+int ForkedCall::startScript(string const & what, sigPtr signal)
 {
-       command_ = what;
+       command_ = commandPrep(trim(what));
        signal_  = signal;
 
        return run(DontWait);
@@ -296,10 +302,11 @@ int ForkedCall::startScript(string const & what, SignalTypePtr signal)
 // generate child in background
 int ForkedCall::generateChild()
 {
-       string line = trim(command_);
-       if (line.empty())
+       if (command_.empty())
                return 1;
 
+       string const prefixed_command = cmd_prefix_ + command_;
+
 #if !defined (_WIN32)
        // POSIX
 
@@ -307,8 +314,8 @@ int ForkedCall::generateChild()
        // in a contiguous block of memory. The array contains pointers
        // to each word.
        // Don't forget the terminating `\0' character.
-       char const * const c_str = line.c_str();
-       vector<char> vec(c_str, c_str + line.size() + 1);
+       char const * const c_str = prefixed_command.c_str();
+       vector<char> vec(c_str, c_str + prefixed_command.size() + 1);
 
        // Splitting the command up into an array of words means replacing
        // the whitespace between words with '\0'. Life is complicated
@@ -319,25 +326,44 @@ int ForkedCall::generateChild()
        // 2. If we are inside quotes, then don't replace the white space
        //    but do remove the quotes themselves. We do this naively by
        //    replacing the quote with '\0' which is fine if quotes
-       //    delimit the entire word.
+       //    delimit the entire word. However, if quotes do not delimit the
+       //    entire word (i.e., open quote is inside word), simply discard
+       //    them such as not to break the current word.
        char inside_quote = 0;
+       char c_before_open_quote = ' ';
        vector<char>::iterator it = vec.begin();
+       vector<char>::iterator itc = vec.begin();
        vector<char>::iterator const end = vec.end();
-       for (; it != end; ++it) {
+       for (; it != end; ++it, ++itc) {
                char const c = *it;
                if (!inside_quote) {
-                       if (c == ' ')
-                               *it = '\0';
-                       else if (c == '\'' || c == '"') {
-                               *it = '\0';
+                       if (c == '\'' || c == '"') {
+                               if (c_before_open_quote == ' ')
+                                       *itc = '\0';
+                               else
+                                       --itc;
                                inside_quote = c;
+                       } else {
+                               if (c == ' ')
+                                       *itc = '\0';
+                               else
+                                       *itc = c;
+                               c_before_open_quote = c;
                        }
                } else if (c == inside_quote) {
-                       *it = '\0';
+                       if (c_before_open_quote == ' ')
+                               *itc = '\0';
+                       else
+                               --itc;
                        inside_quote = 0;
-               }
+               } else
+                       *itc = c;
        }
 
+       // Clear what remains.
+       for (; itc != end; ++itc)
+               *itc = '\0';
+
        // Build an array of pointers to each word.
        it = vec.begin();
        vector<char *> argv;
@@ -347,14 +373,14 @@ int ForkedCall::generateChild()
                        argv.push_back(&*it);
                prev = *it;
        }
-       argv.push_back(0);
+       argv.push_back(nullptr);
 
        // Debug output.
        if (lyxerr.debugging(Debug::FILES)) {
                vector<char *>::iterator ait = argv.begin();
                vector<char *>::iterator const aend = argv.end();
-               lyxerr << "<command>\n\t" << line
-                      << "\n\tInterpretted as:\n\n";
+               lyxerr << "<command>\n\t" << prefixed_command
+                      << "\n\tInterpreted as:\n\n";
                for (; ait != aend; ++ait)
                        if (*ait)
                                lyxerr << '\t'<< *ait << '\n';
@@ -376,15 +402,15 @@ int ForkedCall::generateChild()
 
        pid_t cpid = -1;
 
-       STARTUPINFO startup; 
-       PROCESS_INFORMATION process; 
+       STARTUPINFO startup;
+       PROCESS_INFORMATION process;
 
        memset(&startup, 0, sizeof(STARTUPINFO));
        memset(&process, 0, sizeof(PROCESS_INFORMATION));
-    
+
        startup.cb = sizeof(STARTUPINFO);
 
-       if (CreateProcess(0, (LPSTR)line.c_str(), 0, 0, FALSE,
+       if (CreateProcess(0, (LPSTR)command_.c_str(), 0, 0, FALSE,
                CREATE_NO_WINDOW, 0, 0, &startup, &process)) {
                CloseHandle(process.hThread);
                cpid = (pid_t)process.hProcess;
@@ -409,19 +435,13 @@ int ForkedCall::generateChild()
 namespace ForkedCallQueue {
 
 /// A process in the queue
-typedef pair<string, ForkedCall::SignalTypePtr> Process;
-/** Add a process to the queue. Processes are forked sequentially
- *  only one is running at a time.
- *  Connect to the returned signal and you'll be informed when
- *  the process has ended.
- */
-ForkedCall::SignalTypePtr add(string const & process);
+typedef pair<string, ForkedCall::sigPtr> Process;
 
 /// in-progress queue
 static queue<Process> callQueue_;
 
 /// flag whether queue is running
-static bool running_ = 0;
+static bool running_ = false;
 
 ///
 void startCaller();
@@ -430,10 +450,15 @@ void stopCaller();
 ///
 void callback(pid_t, int);
 
-ForkedCall::SignalTypePtr add(string const & process)
+/** Add a process to the queue. Processes are forked sequentially
+ *  only one is running at a time.
+ *  Connect to the returned signal and you'll be informed when
+ *  the process has ended.
+ */
+ForkedCall::sigPtr add(string const & process)
 {
-       ForkedCall::SignalTypePtr ptr;
-       ptr.reset(new ForkedCall::SignalType);
+       ForkedCall::sigPtr ptr;
+       ptr.reset(new ForkedCall::sig);
        callQueue_.push(Process(process, ptr));
        if (!running_)
                startCaller();
@@ -448,7 +473,7 @@ void callNext()
        Process pro = callQueue_.front();
        callQueue_.pop();
        // Bind our chain caller
-       pro.second->connect(lyx::bind(&ForkedCallQueue::callback, _1, _2));
+       pro.second->connect(callback);
        ForkedCall call;
        //If we fail to fork the process, then emit the signal
        //to tell the outside world that it failed.
@@ -486,8 +511,7 @@ bool running()
        return running_;
 }
 
-} // namespace ForkedCallsQueue
-
+} // namespace ForkedCallQueue
 
 
 /////////////////////////////////////////////////////////////////////
@@ -635,7 +659,7 @@ void handleCompletedProcesses()
                        forkedCalls.erase(it);
                        actCall->emitSignal();
 
-                       /* start all over: emiting the signal can result
+                       /* start all over: emitting the signal can result
                         * in changing the list (Ab)
                         */
                        it = forkedCalls.begin();