PDA

View Full Version : Problem with qprocess



resal
26th August 2007, 17:52
Hi guys,
during my joyful experience with qt, i encountered a problems that it seems doesn't want to be handled! :
I have some (external) console commands that I want to write some GUI for them. when running in a terminal like Konsole, these programs output sequence is :
stderr (prints help message)
stdout (asks what operation I would like to do usually using a menu)
stdin (waiting for my input)

as in


$somecmd
welcome to this program ......... (stderr)
you can use this program this way "somecmd -[dfr] " (stderr)

what do you want to do? (stdout)
1 open a file (stdout)
2 write a file (stdout)
3 exit (stdout)

(stdin waiting for input)

in konsole or xterm everything is fine, but when using qprocess I can not get the menu which is shot out through stdout. So in the GUI, after running program, it prints its stderr messages and without printing stdout menu, is waiting for input. I have tried various methods (merged channels, using DupStderr in q3process, using pipes, ...) but never could have stdout messages which comes before stdin. if I closeWriteChannel() in slot which reads stderr, the menu is printed but this time I dont have accessibility to stdin and program continues using its defaults.

I think the matter is opening stdin closes stdout channel(which seems reasonable) but how can I have those buffered stdouts? Do you know how konsole or other emulators manage this? Do I need to subclass qprocess? Defining child processes may be helpful? how?

Any help, hint or suggestion is quite appreciated.

jacek
26th August 2007, 18:47
How do you read data from QProcess?

resal
26th August 2007, 23:38
I have tried these ones:


m_process->setCommunication( Q3Process::Stdin | Q3Process::Stdout | Q3Process::Stderr | Q3Process::DupStderr);
m_process->start()
while(m_process->canReadLineStdout() )
qDebug()<<m_process->readLineStdout();


connect( m_process, SIGNAL(readyReadStdout()), this, SLOT(readStandardOutput()) )
m_process->setCommunication( Q3Process::Stdin | Q3Process::Stdout | Q3Process::Stderr | Q3Process::DupStderr);
m_process->start();
....
qDebug()<<m_process-> readStdout() [in readStandardOutput() slot]



m_process = new QProcess(this);
m_process->setProcessChannelMode(QProcess::MergedChannels);
connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError()));
connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
startProcess(m_progname);
...
qDebug()<< QString(m_process->readAllStandardError()); [readStandardError() slot]
...
qDebug()<< QString(m_process->readAllStandardOutput()); [readStandardOutput() slot]
...

[as I said if I close write channel in readStandardError() slot, I will get those lines ]


I even tried to redirect outputs to files, but again no success in getting those lines before stdin prompt. Am I doing something wrong?

I have reviewed some codes of others (both qt3 and qt4) especially codes of IDEs but no success. I would be happy even if you point me some where (code, thread..) to learn more.
I tried Google and Koders, but no success again.

Besides, is there any non-qt work-around for this problem? Do you know some pure C++ console like code, which is wrapped in qt?

jacek
27th August 2007, 00:43
m_process->setProcessChannelMode(QProcess::MergedChannels);
Shouldn't you use QProcess::SeparateChannels here (i.e. the default mode)?

What do the "out" and "err" files contain after you do the following?

$ echo "3" > in # or whatever command is for "do nothing and exit"
$ thatcmd < in > out 2> err

resal
27th August 2007, 01:15
Shouldn't you use QProcess::SeparateChannels here (i.e. the default mode)?
I tried separate channels first, but to make stdout unbuffered, I used merged channel too. no success in both.


What do the "out" and "err" files contain after you do the following?
what that they expected to have. stderr messages in err file, and stdout menu in out file.[ My fault: when I said no success in getting those lines in redirections, I meant that I couldn't have those lines BEFORE writing to stdin. The problem is to have menu then providing input based on this menu.]

resal
27th August 2007, 10:08
Do you know any (not-very-complicated) (especially in Qt4) application with similar functionality? I mean an application which is a GUI that runs some commands AND communicates with those commands while they are still running(i.e. it doesn't wait for commands to finish and then gets the output; rather it gets the messages of commands during execution, displays the messages to user and then writes user options to command stdin). I reviewed konsole code, but got lost in (kde-related) classes....

thanks

jacek
28th August 2007, 01:44
what that they expected to have. stderr messages in err file, and stdout menu in out file.
OK, so at least that application isn't playing any tricks by detecting whether the input comes from a file or a terminal.

There is no way to control the buffers through QProcess, but maybe reimplementing QProcess::setupChildProcess() will help. You might try to alter the buffer size with setbuf, but I'm not sure if it's going to work (I think I've tried it to solve a similar problem, but without a success).


Do you know any (not-very-complicated) (especially in Qt4) application with similar functionality?
Unfortunately, I don't.


I reviewed konsole code, but got lost in (kde-related) classes....
kconsole doesn't use pure QProcess, but a K3Process subclass. The most important difference is that KDE allows you to use a pty device to communicate with the child process.

Here are the relevant sources:
http://websvn.kde.org/trunk/KDE/kdebase/apps/konsole/src/Pty.h?view=markup
http://websvn.kde.org/trunk/KDE/kdebase/apps/konsole/src/Pty.cpp?view=markup
http://api.kde.org/4.0-api/kdelibs-apidocs/kdecore/html/k3process_8h.html
http://api.kde.org/4.0-api/kdelibs-apidocs/kdecore/html/classKPty.html

resal
28th August 2007, 03:17
Thank you jacek.


Here are the relevant sources:
http://websvn.kde.org/trunk/KDE/kdebase/apps/konsole/src/Pty.h?view=markup
http://websvn.kde.org/trunk/KDE/kdebase/apps/konsole/src/Pty.cpp?view=markup
http://api.kde.org/4.0-api/kdelibs-apidocs/kdecore/html/k3process_8h.html
http://api.kde.org/4.0-api/kdelibs-apidocs/kdecore/html/classKPty.html

I have reviewed them before. As you said the trick in konsole is using kpty device.



There is no way to control the buffers through QProcess, but maybe reimplementing QProcess::setupChildProcess() will help. You might try to alter the buffer size with setbuf, but I'm not sure if it's going to work (I think I've tried it to solve a similar problem, but without a success).

I think this is the case. I 've played with setupChild Process() but I couldn't figured it out how to use it. I found these links though :
http://labs.trolltech.com/blogs/2006/03/16/starting-interactive-processes-with-qprocess/
http://www.koders.com/default.aspx?s=setupchildprocess&btn=Search&la=*&li=*
http://www.koders.com/cpp/fidCB4E6B700F38BC18E4C560899C36BB13E281ED75.aspx?s =setupchildprocess

The first one, I think, is the solution. I tried to find some example of its usage, so I search koders, which didn't help me a lot.

Can anyone write an example code about how to use the method that first link suggest?

Thanks in advance.

jacek
29th August 2007, 22:13
I think this is the case. I 've played with setupChild Process() but I couldn't figured it out how to use it.
You have to create a QProcess subclass and use that new class instead.

class UnbufferedProcess : public QProcess
{
protected:
void setupChildProcess()
{
::setbuf( stdout, 0 );
}
};
But as I said, I'm not sure if it's going to help.


The first one, I think, is the solution. I tried to find some example of its usage, so I search koders, which didn't help me a lot.
You use it just like QProcess, but I'm not sure if it solves your problem. I think that this class is useful if the process you want to start insists on reading from the terminal. Nevertheless, try it.