From: Enrico Forestieri Date: Thu, 14 May 2009 15:13:58 +0000 (+0000) Subject: Allow immediate output of spawned processes for all platforms. X-Git-Tag: 2.0.0~6573 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=8fe984090fc1f998bffe1e7c2c3ff86bcf657ab5;p=features.git Allow immediate output of spawned processes for all platforms. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@29668 a592a061-630c-0410-9148-cb99ea01b6c8 --- diff --git a/src/support/Makefile.am b/src/support/Makefile.am index 3e66033981..4001cf8f15 100644 --- a/src/support/Makefile.am +++ b/src/support/Makefile.am @@ -12,7 +12,7 @@ BUILT_SOURCES = $(PCH_FILE) ######################### Qt stuff ############################# # -MOCHEADER = SignalSlotPrivate.h +MOCHEADER = SignalSlotPrivate.h Systemcall.h MOCEDFILES = $(MOCHEADER:%.h=moc_%.cpp) diff --git a/src/support/Systemcall.cpp b/src/support/Systemcall.cpp index 3db5fd0a40..7ca8869c4c 100644 --- a/src/support/Systemcall.cpp +++ b/src/support/Systemcall.cpp @@ -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 diff --git a/src/support/Systemcall.h b/src/support/Systemcall.h index 61ba092a2d..2205ebc9b2 100644 --- a/src/support/Systemcall.h +++ b/src/support/Systemcall.h @@ -16,6 +16,9 @@ #define SYSTEMCALL_H #include +#include + +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 diff --git a/src/support/os.h b/src/support/os.h index 1644ef4bf0..cbfd7c5d03 100644 --- a/src/support/os.h +++ b/src/support/os.h @@ -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); diff --git a/src/support/os_cygwin.cpp b/src/support/os_cygwin.cpp index 068d7035d6..5fe8df378e 100644 --- a/src/support/os_cygwin.cpp +++ b/src/support/os_cygwin.cpp @@ -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); diff --git a/src/support/os_unix.cpp b/src/support/os_unix.cpp index a9ae59850c..eb8c1dfa4e 100644 --- a/src/support/os_unix.cpp +++ b/src/support/os_unix.cpp @@ -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); diff --git a/src/support/os_win32.cpp b/src/support/os_win32.cpp index 464d8df111..a204adfde0 100644 --- a/src/support/os_win32.cpp +++ b/src/support/os_win32.cpp @@ -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; }