]> git.lyx.org Git - lyx.git/blobdiff - src/support/ForkedCalls.cpp
Add missing header
[lyx.git] / src / support / ForkedCalls.cpp
index 592053b6cf23a6fe04d03ed14f5fa976f5380c7b..fc2b599484ef89ee8d3dff76991863583ad54ff2 100644 (file)
@@ -21,7 +21,7 @@
 #include "support/os.h"
 #include "support/Timeout.h"
 
-#include <boost/bind.hpp>
+#include "support/bind.h"
 
 #include <cerrno>
 #include <queue>
@@ -46,7 +46,7 @@
 
 using namespace std;
 
-using boost::bind;
+
 
 namespace lyx {
 namespace support {
@@ -59,7 +59,7 @@ namespace {
 //
 /////////////////////////////////////////////////////////////////////
 
-class Murder : public boost::signals::trackable {
+class Murder : public boost::signals2::trackable {
 public:
        //
        static void killItDead(int secs, pid_t pid)
@@ -84,7 +84,7 @@ private:
        Murder(int secs, pid_t pid)
                : timeout_(1000*secs, Timeout::ONETIME), pid_(pid)
        {
-               timeout_.timeout.connect(boost::bind(&Murder::kill, this));
+               timeout_.timeout.connect(lyx::bind(&Murder::kill, this));
                timeout_.start();
        }
 
@@ -113,7 +113,7 @@ bool ForkedProcess::IAmAChild = false;
 
 void ForkedProcess::emitSignal()
 {
-       if (signal_.get()) {
+       if (signal_) {
                signal_->operator()(pid_, retval_);
        }
 }
@@ -150,7 +150,7 @@ int ForkedProcess::run(Starttype type)
 
 bool ForkedProcess::running() const
 {
-       if (!pid())
+       if (pid() <= 0)
                return false;
 
 #if !defined (_WIN32)
@@ -170,7 +170,7 @@ bool ForkedProcess::running() const
 void ForkedProcess::kill(int tol)
 {
        lyxerr << "ForkedProcess::kill(" << tol << ')' << endl;
-       if (pid() == 0) {
+       if (pid() <= 0) {
                lyxerr << "Can't kill non-existent process!" << endl;
                return;
        }
@@ -192,13 +192,7 @@ void ForkedProcess::kill(int tol)
 
 
 pid_t ForkedProcess::fork() {
-/* FIXME fork() is not usable on Mac OS X 10.6 (snow leopard) 
- *   Use something else like threads.
- *
- * Since I do not know how to determine at run time what is the OS X
- * version, I just disable forking altogether for now (JMarc)
- */
-#if !defined (HAVE_FORK) || defined(__APPLE__)
+#if !defined (HAVE_FORK)
        return -1;
 #else
        pid_t pid = ::fork();
@@ -276,6 +270,10 @@ 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)
 {
@@ -284,7 +282,7 @@ int ForkedCall::startScript(Starttype wait, string const & what)
                return retval_;
        }
 
-       command_ = what;
+       command_ = commandPrep(trim(what));
        signal_.reset();
        return run(Wait);
 }
@@ -292,7 +290,7 @@ int ForkedCall::startScript(Starttype wait, string const & what)
 
 int ForkedCall::startScript(string const & what, SignalTypePtr signal)
 {
-       command_ = what;
+       command_ = commandPrep(trim(what));
        signal_  = signal;
 
        return run(DontWait);
@@ -302,10 +300,17 @@ 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;
 
+       // Make sure that a V2 python is run, if available.
+       string const line = cmd_prefix_ +
+               (prefixIs(command_, "python -tt")
+                ? os::python() + command_.substr(10) : command_);
+
+#if !defined (_WIN32)
+       // POSIX
+
        // Split the input command up into an array of words stored
        // in a contiguous block of memory. The array contains pointers
        // to each word.
@@ -322,37 +327,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 == '"') {
-#if defined (_WIN32)
-                               // How perverse!
-                               // spawnvp *requires* the quotes or it will
-                               // split the arg at the internal whitespace!
-                               // Make shure the quote is a DOS-style one.
-                               *it = '"';
-#else
-                               *it = '\0';
-#endif
+                       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) {
-#if defined (_WIN32)
-                       *it = '"';
-#else
-                       *it = '\0';
-#endif
+                       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;
@@ -369,16 +381,13 @@ int ForkedCall::generateChild()
                vector<char *>::iterator ait = argv.begin();
                vector<char *>::iterator const aend = argv.end();
                lyxerr << "<command>\n\t" << line
-                      << "\n\tInterpretted as:\n\n";
+                      << "\n\tInterpreted as:\n\n";
                for (; ait != aend; ++ait)
                        if (*ait)
                                lyxerr << '\t'<< *ait << '\n';
                lyxerr << "</command>" << endl;
        }
 
-#ifdef _WIN32
-       pid_t const cpid = spawnvp(_P_NOWAIT, argv[0], &*argv.begin());
-#else // POSIX
        pid_t const cpid = ::fork();
        if (cpid == 0) {
                // Child
@@ -389,6 +398,24 @@ int ForkedCall::generateChild()
                       << strerror(errno) << endl;
                _exit(1);
        }
+#else
+       // Windows
+
+       pid_t cpid = -1;
+
+       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,
+               CREATE_NO_WINDOW, 0, 0, &startup, &process)) {
+               CloseHandle(process.hThread);
+               cpid = (pid_t)process.hProcess;
+       }
 #endif
 
        if (cpid < 0) {
@@ -448,7 +475,7 @@ void callNext()
        Process pro = callQueue_.front();
        callQueue_.pop();
        // Bind our chain caller
-       pro.second->connect(boost::bind(&ForkedCallQueue::callback, _1, _2));
+       pro.second->connect(lyx::bind(&ForkedCallQueue::callback, _1, _2));
        ForkedCall call;
        //If we fail to fork the process, then emit the signal
        //to tell the outside world that it failed.
@@ -526,7 +553,7 @@ string const getChildErrorMessage()
 
 namespace ForkedCallsController {
 
-typedef boost::shared_ptr<ForkedProcess> ForkedProcessPtr;
+typedef std::shared_ptr<ForkedProcess> ForkedProcessPtr;
 typedef list<ForkedProcessPtr> ListType;
 typedef ListType::iterator iterator;
 
@@ -537,8 +564,8 @@ static ListType forkedCalls;
 iterator find_pid(pid_t pid)
 {
        return find_if(forkedCalls.begin(), forkedCalls.end(),
-                      bind(equal_to<pid_t>(),
-                           bind(&ForkedCall::pid, _1),
+                           lyx::bind(equal_to<pid_t>(),
+                           lyx::bind(&ForkedCall::pid, _1),
                            pid));
 }
 
@@ -577,6 +604,7 @@ void handleCompletedProcesses()
                        } else {
                                actCall->setRetValue(exit_code);
                        }
+                       CloseHandle(hProcess);
                        remove_it = true;
                        break;
                }
@@ -584,6 +612,7 @@ void handleCompletedProcesses()
                        lyxerr << "WaitForSingleObject failed waiting for child\n"
                               << getChildErrorMessage() << endl;
                        actCall->setRetValue(1);
+                       CloseHandle(hProcess);
                        remove_it = true;
                        break;
                }