On Mon, Oct 31, 2011 at 03:02:28AM +0100, for...@lyx.org wrote: > Author: forenr > Date: Mon Oct 31 03:02:27 2011 > New Revision: 40110 > URL: http://www.lyx.org/trac/changeset/40110 > > Log: > Properly account for output redirection with QProcess.
This is also needed in branch. > Modified: > lyx-devel/trunk/src/support/Systemcall.cpp > lyx-devel/trunk/src/support/SystemcallPrivate.h > > Modified: lyx-devel/trunk/src/support/Systemcall.cpp > ============================================================================== > --- lyx-devel/trunk/src/support/Systemcall.cpp Mon Oct 31 02:58:58 > 2011 (r40109) > +++ lyx-devel/trunk/src/support/Systemcall.cpp Mon Oct 31 03:02:27 > 2011 (r40110) > @@ -128,8 +128,10 @@ > namespace { > > /* > - * This is a parser that (mostly) mimics the behavior of a posix shell but > - * its output is tailored for being processed by QProcess. > + * This is a parser that (mostly) mimics the behavior of a posix shell as > + * regards quoting, but its output is tailored for being processed by > QProcess. > + * Note that shell metacharacters are not parsed and only output redirection > + * is taken into account. > * > * The escape character is the backslash. > * A backslash that is not quoted preserves the literal value of the > following > @@ -162,58 +164,67 @@ > * "\a" -> "\a" > * "a\"b" -> "a"""b" > */ > -string const parsecmd(string const & inputcmd, string & outfile) > +string const parsecmd(string const & incmd, string & outfile, string & > errfile) > { > bool in_single_quote = false; > bool in_double_quote = false; > bool escaped = false; > string const python_call = "python -tt"; > - string cmd; > - int start = 0; > + vector<string> outcmd(3); > + size_t start = 0; > > - if (prefixIs(inputcmd, python_call)) { > - cmd = os::python(); > + if (prefixIs(incmd, python_call)) { > + outcmd[0] = os::python(); > start = python_call.length(); > } > > - for (size_t i = start; i < inputcmd.length(); ++i) { > - char c = inputcmd[i]; > + for (size_t i = start, o = 0; i < incmd.length(); ++i) { > + char c = incmd[i]; > if (c == '\'') { > if (in_double_quote || escaped) { > if (in_double_quote && escaped) > - cmd += '\\'; > - cmd += c; > + outcmd[o] += '\\'; > + outcmd[o] += c; > } else > in_single_quote = !in_single_quote; > escaped = false; > continue; > } > if (in_single_quote) { > - cmd += c; > + outcmd[o] += c; > continue; > } > if (c == '"') { > if (escaped) { > - cmd += "\"\"\""; > + // Don't triple double-quotes for redirection > + // files as these won't be parsed by QProcess > + outcmd[o] += string(o ? "\"" : "\"\"\""); > escaped = false; > } else { > - cmd += c; > + outcmd[o] += c; > in_double_quote = !in_double_quote; > } > } else if (c == '\\' && !escaped) { > escaped = !escaped; > } else if (c == '>' && !(in_double_quote || escaped)) { > - outfile = trim(inputcmd.substr(i + 1), " \""); > - return trim(cmd); > + 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 (escaped && in_double_quote) > - cmd += '\\'; > - cmd += c; > + outcmd[o] += '\\'; > + outcmd[o] += c; > escaped = false; > } > } > - outfile.erase(); > - return cmd; > + outfile = trim(outcmd[1], " \""); > + errfile = trim(outcmd[2], " \""); > + return trim(outcmd[0]); > } > > } // namespace anon > @@ -223,10 +234,14 @@ > int Systemcall::startscript(Starttype how, string const & what, > string const & path, bool process_events) > { > + lyxerr << "\nRunning: " << what << endl; > + > string outfile; > - QString cmd = QString::fromLocal8Bit(parsecmd(what, outfile).c_str()); > + string errfile; > + QString cmd = QString::fromLocal8Bit( > + parsecmd(what, outfile, errfile).c_str()); > > - SystemcallPrivate d(outfile); > + SystemcallPrivate d(outfile, errfile); > > > d.startProcess(cmd, path); > @@ -259,17 +274,60 @@ > } > > > -SystemcallPrivate::SystemcallPrivate(const std::string& of) : > - process_(new QProcess), > - out_index_(0), > - err_index_(0), > - out_file_(of), > - process_events_(false) > +SystemcallPrivate::SystemcallPrivate(std::string const & of, > + std::string const & ef) : > + process_(new QProcess), > + out_index_(0), > + err_index_(0), > + out_file_(of), > + err_file_(ef), > + process_events_(false) > { > if (!out_file_.empty()) { > - // Check whether we have to simply throw away the output. > - if (out_file_ != os::nulldev()) > - > process_->setStandardOutputFile(QString::fromLocal8Bit(out_file_.c_str())); > + if (out_file_[0] == '&') { > + if (subst(out_file_, " ", "") == "&2" > + && err_file_[0] != '&') { > + out_file_ = err_file_; > + process_->setProcessChannelMode( > + QProcess::MergedChannels); > + } else { > + if (err_file_[0] == '&') { > + // Leave alone things such as > + // "1>&2 2>&1". Should not be harmful, > + // but let's give anyway a warning. > + LYXERR0("Unsupported stdout/stderr > redirect."); > + err_file_.erase(); > + } else { > + LYXERR0("Ambiguous stdout redirect: " > + << out_file_); > + } > + out_file_ = os::nulldev(); > + } > + } > + // Check whether we have to set the output file. > + if (out_file_ != os::nulldev()) { > + process_->setStandardOutputFile(QString::fromLocal8Bit( > + out_file_.c_str())); > + } > + } > + if (!err_file_.empty()) { > + if (err_file_[0] == '&') { > + if (subst(err_file_, " ", "") == "&1" > + && out_file_[0] != '&') { > + process_->setProcessChannelMode( > + QProcess::MergedChannels); > + } else { > + LYXERR0("Ambiguous stderr redirect: " > + << err_file_); > + } > + // In MergedChannels mode stderr goes to stdout. > + err_file_ = os::nulldev(); > + } > + // Check whether we have to set the error file. > + if (err_file_ != os::nulldev()) { > + process_->setStandardErrorFile(QString::fromLocal8Bit( > + err_file_.c_str())); > + } > } > > connect(process_, SIGNAL(readyReadStandardOutput()), SLOT(stdOut())); > > Modified: lyx-devel/trunk/src/support/SystemcallPrivate.h > ============================================================================== > --- lyx-devel/trunk/src/support/SystemcallPrivate.h Mon Oct 31 02:58:58 > 2011 (r40109) > +++ lyx-devel/trunk/src/support/SystemcallPrivate.h Mon Oct 31 03:02:27 > 2011 (r40110) > @@ -32,7 +32,7 @@ > Q_OBJECT > > public: > - SystemcallPrivate(std::string const & outfile); > + SystemcallPrivate(std::string const & outfile, std::string const & > errfile); > ~SystemcallPrivate(); > > enum State { > @@ -74,6 +74,8 @@ > size_t err_index_; > /// > std::string out_file_; > + /// > + std::string err_file_; > > /// Size of buffers. > static size_t const buffer_size_ = 200; -- Enrico