]> git.lyx.org Git - features.git/commitdiff
Allow immediate output of spawned processes for all platforms.
authorEnrico Forestieri <forenr@lyx.org>
Thu, 14 May 2009 15:13:58 +0000 (15:13 +0000)
committerEnrico Forestieri <forenr@lyx.org>
Thu, 14 May 2009 15:13:58 +0000 (15:13 +0000)
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@29668 a592a061-630c-0410-9148-cb99ea01b6c8

src/support/Makefile.am
src/support/Systemcall.cpp
src/support/Systemcall.h
src/support/os.h
src/support/os_cygwin.cpp
src/support/os_unix.cpp
src/support/os_win32.cpp

index 3e660339812c55e41b077d799e84692358b78a6c..4001cf8f15c5e9dc6f89c1fe8c77afb5936a33b7 100644 (file)
@@ -12,7 +12,7 @@ BUILT_SOURCES = $(PCH_FILE)
 #########################  Qt stuff  #############################
 #
 
-MOCHEADER = SignalSlotPrivate.h
+MOCHEADER = SignalSlotPrivate.h Systemcall.h
 
 MOCEDFILES = $(MOCHEADER:%.h=moc_%.cpp)
 
index 3db5fd0a40d04783eee074aae948b3be63ab1a46..7ca8869c4c5ea525aa6625f7966d9627d2254c9e 100644 (file)
@@ -33,6 +33,7 @@ namespace support {
 
 static void killProcess(QProcess * p)
 {
+       p->disconnect();
        p->closeReadChannel(QProcess::StandardOutput);
        p->closeReadChannel(QProcess::StandardError);
        p->close();
@@ -83,7 +84,6 @@ string const parsecmd(string const & cmd, string & outfile)
        }
        outfile.erase();
        return cmd;
-
 }
 
 } // namespace anon
@@ -94,18 +94,15 @@ int Systemcall::startscript(Starttype how, string const & what)
        string outfile;
        QString cmd = toqstr(parsecmd(what, outfile));
        QProcess * process = new QProcess;
-
-       // Qt won't start the process if we redirect stdout/stderr in
-       // this way and they are not connected to a terminal (maybe
-       // because we were launched from some desktop GUI).
+       ConOut console(process);
        if (!outfile.empty()) {
                // Check whether we have to simply throw away the output.
                if (outfile != os::nulldev())
                        process->setStandardOutputFile(toqstr(outfile));
        } else if (os::is_terminal(os::STDOUT))
-               process->setStandardOutputFile(toqstr(os::stdoutdev()));
+               console.showout();
        if (os::is_terminal(os::STDERR))
-               process->setStandardErrorFile(toqstr(os::stderrdev()));
+               console.showerr();
 
        process->start(cmd);
        if (!process->waitForStarted(3000)) {
@@ -115,8 +112,10 @@ int Systemcall::startscript(Starttype how, string const & what)
                LYXERR0("status " << process->exitStatus());
                return 10;
        }
-       if (how == DontWait)
+       if (how == DontWait) {
+               // TODO delete process later
                return 0;
+       }
 
        if (!process->waitForFinished(180000)) {
                LYXERR0("Qprocess " << cmd << " did not finished!");
@@ -147,6 +146,57 @@ int Systemcall::startscript(Starttype how, string const & what)
        killProcess(process);
        return exit_code;
 }
+
+
+ConOut::ConOut(QProcess * proc) : proc_(proc), outindex_(0), errindex_(0),
+                                 showout_(false), showerr_(false)
+{
+       connect(proc, SIGNAL(readyReadStandardOutput()), SLOT(stdOut()));
+       connect(proc, SIGNAL(readyReadStandardError()), SLOT(stdErr()));
+}
+
+
+ConOut::~ConOut()
+{
+       cout.flush();
+       cerr.flush();
+}
+
+
+void ConOut::stdOut()
+{
+       if (showout_) {
+               char c;
+               proc_->setReadChannel(QProcess::StandardOutput);
+               while (proc_->getChar(&c)) {
+                       outdata_[outindex_++] = c;
+                       if (c == '\n' || outindex_ + 1 == bufsize_) {
+                               outdata_[outindex_] = '\0';
+                               outindex_ = 0;
+                               cout << outdata_;
+                       }
+               }
+       }
+}
+
+
+void ConOut::stdErr()
+{
+       if (showerr_) {
+               char c;
+               proc_->setReadChannel(QProcess::StandardError);
+               while (proc_->getChar(&c)) {
+                       errdata_[errindex_++] = c;
+                       if (c == '\n' || errindex_ + 1 == bufsize_) {
+                               errdata_[errindex_] = '\0';
+                               errindex_ = 0;
+                               cerr << errdata_;
+                       }
+               }
+       }
+}
+
+#include "moc_Systemcall.cpp"
 #endif
 
 } // namespace support
index 61ba092a2dde0a3c93296de11a6650569faea15c..2205ebc9b2a780fa62daa39058962a2abe0cd29d 100644 (file)
@@ -16,6 +16,9 @@
 #define SYSTEMCALL_H
 
 #include <string>
+#include <QObject>
+
+class QProcess;
 
 namespace lyx {
 namespace support {
@@ -45,6 +48,48 @@ public:
        int startscript(Starttype how, std::string const & what);
 };
 
+
+/**
+ * Outputs to the console terminal the line buffered standard output and
+ * error of a spawned process when there is a controlling terminal and 
+ * stdout/stderr have not been redirected.
+ */
+class ConOut : public QObject
+{
+       Q_OBJECT
+public:
+       ConOut(QProcess * proc);
+       ~ConOut();
+
+       /// Should the standard output be displayed?
+       void showout() { showout_ = true; }
+
+       /// Should the standard error be displayed?
+       void showerr() { showerr_ = true; }
+
+private:
+       /// Pointer to the process to monitor.
+       QProcess * proc_;
+       /// Index to the standard output buffer.
+       size_t outindex_;
+       /// Index to the standard error buffer.
+       size_t errindex_;
+       /// Size of buffers.
+       static size_t const bufsize_ = 200;
+       /// Standard output buffer.
+       char outdata_[bufsize_];
+       /// Standard error buffer.
+       char errdata_[bufsize_];
+       /// 
+       bool showout_;
+       /// 
+       bool showerr_;
+
+public Q_SLOTS:
+       void stdOut();
+       void stdErr();
+};
+
 } // namespace support
 } // namespace lyx
 
index 1644ef4bf001eac42a13bae957aa28999736e720..cbfd7c5d03119ccfadfb0711e7326b1665532792 100644 (file)
@@ -39,12 +39,6 @@ void init(int argc, char * argv[]);
 /// Returns the name of the NULL device (/dev/null, null).
 std::string const & nulldev();
 
-/// Returns the name of the stdout device (/dev/stdout, /dev/tty, conout$).
-std::string const & stdoutdev();
-
-/// Returns the name of the stderr device (/dev/stderr, /dev/tty, conout$).
-std::string const & stderrdev();
-
 /// Tells whether \p channel is connected to a terminal or not. 
 bool is_terminal(io_channel channel);
 
index 068d7035d685c373f10f16e92b8fd3442194bbc2..5fe8df378eb00e610eddef3a1409cca44d9defee 100644 (file)
@@ -240,20 +240,6 @@ string const & nulldev()
 }
 
 
-string const & stdoutdev()
-{
-       static string const stdoutdev_ = "/dev/stdout";
-       return stdoutdev_;
-}
-
-
-string const & stderrdev()
-{
-       static string const stderrdev_ = "/dev/stderr";
-       return stderrdev_;
-}
-
-
 bool is_terminal(io_channel channel)
 {
        return isatty(channel);
index a9ae59850cb37ecd4cc735d754572f49000fe706..eb8c1dfa4e3440433002c6ad76538ddd7b4687cd 100644 (file)
@@ -30,23 +30,8 @@ namespace lyx {
 namespace support {
 namespace os {
 
-namespace {
-
-string stdoutdev_ = "/dev/stdout";
-string stderrdev_ = "/dev/stderr";
-
-} // namespace anon
-
 void init(int, char *[])
-{
-       // Check whether /dev/stdout and /dev/stderr are available,
-       // otherwise default to /dev/tty.
-       if (access(stdoutdev_.c_str(), W_OK) != 0
-           || access(stderrdev_.c_str(), W_OK) != 0) {
-               stdoutdev_ = "/dev/tty";
-               stderrdev_ = "/dev/tty";
-       }
-}
+{}
 
 
 string current_root()
@@ -145,18 +130,6 @@ string const & nulldev()
 }
 
 
-string const & stdoutdev()
-{
-       return stdoutdev_;
-}
-
-
-string const & stderrdev()
-{
-       return stderrdev_;
-}
-
-
 bool is_terminal(io_channel channel)
 {
        return isatty(channel);
index 464d8df1114e0a20d80363aa47da4d22fc2ebf96..a204adfde094fe5b7b70fd0cbddcb181a863cedc 100644 (file)
@@ -296,28 +296,23 @@ string const & nulldev()
 }
 
 
-string const & stdoutdev()
-{
-       static string const stdoutdev_ = "conout$";
-       return stdoutdev_;
-}
-
-
-string const & stderrdev()
-{
-       static string const stderrdev_ = "conout$";
-       return stderrdev_;
-}
-
-
 bool is_terminal(io_channel channel)
 {
-       // FIXME: Passing conout$ to Qt fails, most probably for the
-       // reason explained here:
-       // http://support.microsoft.com/?scid=kb%3Ben-us%3B90088&x=15&y=15
-       // How to convince Qt to open conout$ in FILE_SHARE_WRITE mode?
-       // For the time being, we assume we are not running in a terminal.
-       return false;
+       switch (channel) {
+       case STDIN:
+               if (GetStdHandle(STD_INPUT_HANDLE) == NULL)
+                       return false;
+               break;
+       case STDOUT:
+               if (GetStdHandle(STD_OUTPUT_HANDLE) == NULL)
+                       return false;
+               break;
+       case STDERR:
+               if (GetStdHandle(STD_ERROR_HANDLE) == NULL)
+                       return false;
+               break;
+       }
+       return true;
 }