PDA

View Full Version : Standard error and standard output from QProcess in wrong order



StCrocco
31st May 2008, 18:15
I'm trying to write an editor for the ruby programming language using Qt 4. This editor should be able to run a ruby script written by the user and display the output and error messages from the script in a QListView, using a different color for the latter. To do this, I use a QProcess. I connect the readyReadStandardError and readyReadStandardOutput signals from the process with two slots which set the read channel respectively to StandardError and StandardOutput, read the content of the channel and display them.

Having written this code, I tried running a ruby script which, for 10 times, writes a string to standard error and one to standard output. The result should have been this:

warning 0
message 0
warning 1
message 1
...
warning 9
message 9

where the warnings are the text written to standard error and the messages are the text written to standard output. Instead, what I got is this:


warning 0
warning 1
...
warning 9
message 0
message 1
...
message 9


Besides, the slots connected to the readyStandardError and readyStandardOutput are called only once, while I expected each of them to be called ten times (one for each message). Does anyone know what I'm doing wrong or how to achieve the result I want?

Here's a simplified version of the application. It consists of a simple QPushButton which launches the ruby script and writes the output to the terminal.

This is the header file for the MyApp class, which contains the QProcess:


#ifndef MYAPP_H
#define MYAPP_H

#include <QApplication>
#include <QProcess>

class MyApp: public QApplication{

Q_OBJECT

public:

MyApp(int argc, char ** argv);
~MyApp();

public slots:
void displayOutputMsg();
void displayErrorMsg();
void runRuby();

private:
QProcess * m_proc;
};

#endif

and here's the implementation:


#include "app.h"
#include <iostream>
#include <string>
#include <QStringList>

MyApp::MyApp(int argc, char ** argv): QApplication(argc, argv), m_proc(new QProcess(this)){
connect(m_proc, SIGNAL(readyReadStandardOutput()),this, SLOT(displayOutputMsg()));
connect(m_proc, SIGNAL(readyReadStandardError()),this, SLOT(displayErrorMsg()));
}

MyApp::~MyApp(){}

void MyApp::displayOutputMsg(){
m_proc->setReadChannel(QProcess::StandardOutput);
QByteArray msg = m_proc->read(1000);
std::cout << "Output: "<< (msg.data())<<"\n";
}

void MyApp::displayErrorMsg(){
m_proc->setReadChannel(QProcess::StandardError);
QByteArray msg = m_proc->read(1000);
std::cout << "Error: "<< (msg.data())<<"\n";
}

void MyApp::runRuby(){
QStringList args;
args << "-w" << "/home/stefano/documenti/scripts/prova.rb";
m_proc->start("ruby", args);
}


This is the main.cpp file:


#include "app.h"
#include <QPushButton>
#include <QWidget>
#include <QLayout>

int main(int argc, char ** argv){
MyApp * app = new MyApp(argc, argv);
QWidget * w = new QWidget;
QLayout * l = new QHBoxLayout(w);
QPushButton * ruby = new QPushButton("Run &ruby", w);
l->addWidget(ruby);
// QPushButton * python = new QPushButton("Run &python", w);
// l->addWidget(python);
app->connect( ruby, SIGNAL(clicked()), SLOT(runRuby()));
// app->connect( python, SIGNAL(clicked()), SLOT(runPython()));
w->show();
app->exec();
}


Thanks in advance

ktk
31st May 2008, 23:57
That's what you see is probably indeed what the Ruby application produces. I have no idea how Ruby works, but for "usual" C programs stdout and stderr are typically not connected to each other, and stdout is typically buffered whereas stderr is not. So getting all stderr before the stdout buffer is flushed is not uncommon, also merging "packets" is not.

So to get what you want to you need either to flush after each output operation or to (a) un-buffer stderr and (b) synchronize stderr and stdout, both in the Ruby application.

StCrocco
2nd June 2008, 08:45
Thanks for your answer. Since I'm writing a ruby editor, the ruby application will be written by the user, not by me, so I can't change it. At any rate, I tried executing my test ruby script from other editors (kdevelop, scite, netbeans) and they give the same output mine gives, so I guess there's nothing I can do about it.