/*
* process.cc
*
* Copyright (c) 2003 Frerich Raabe <raabe@kde.org>
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. For licensing and distribution details, check the
* accompanying file 'COPYING'.
*/
#include "process.h"
#include <kdebug.h>
#include <klocale.h>
#if __FreeBSD__ == 5
# include <ktempfile.h>
#endif
#include <ktextedit.h>
#if __FreeBSD__ == 5
# include <qfile.h>
#endif
#include <qvbox.h>
using namespace Barry;
QString Process::execute( const QString &command, Communication comm, bool *ok )
{
Process proc;
return proc.runBlocking( command, comm, ok );
}
QString Process::execute( const QStringList &command, Communication comm, bool *ok )
{
Process proc;
return proc.runBlocking( command, comm, ok );
}
Process::Process()
: m_process( 0 )
{
#if __FreeBSD__ == 5
m_stdoutTempFile = 0;
m_stderrTempFile = 0;
#endif
}
QString Process::runBlocking( const QString &command, Communication comm,
bool *ok )
{
return runBlocking( QStringList::split( ' ', command ), comm, ok );
}
QString Process::runBlocking( const QStringList &command, Communication comm,
bool *ok )
{
m_buffer = QString::null;
KProcess proc;
proc << command;
/* Work around something which seems to be a bug in FreeBSD 5.x :
* KProcess cannot return the output of the child process through the
* signals. Instead, we pipe the output of the command into a temporary
* file, and then return the contents of that file.
*/
#if __FreeBSD__ != 5
if ( comm & Stdout )
connect( &proc, SIGNAL( receivedStdout( KProcess *, char *, int ) ),
this, SLOT( slotReceivedOutput( KProcess *, char *, int ) ) );
if ( comm & Stderr )
connect( &proc, SIGNAL( receivedStderr( KProcess *, char *, int ) ),
this, SLOT( slotReceivedOutput( KProcess *, char *, int ) ) );
// C-style cast because gcc 2.95.4 is buggy and won't allow static_cast
proc.start( KProcess::Block, ( KProcess::Communication )comm );
#else
KTempFile tempFile;
tempFile.setAutoDelete( true );
if ( comm & Stdout && comm & Stderr )
proc << ">" << tempFile.name() << "2>&1";
else if ( comm & Stdout )
proc << "1>" << tempFile.name();
else // comm & Stderr
proc << "2>" << tempFile.name();
proc.setUseShell( true );
proc.start( KProcess::Block );
#endif
if ( ok != 0 )
*ok = proc.normalExit() && proc.exitStatus() == 0;
#if __FreeBSD__ != 5
return m_buffer;
#else
const QByteArray data = tempFile.file()->readAll();
return QString::fromLocal8Bit( data.data(), data.size() );
#endif
}
void Process::run( const QString &command, Communication comm )
{
run( QStringList::split( ' ', command ), comm );
}
void Process::run( const QStringList &command, Communication comm )
{
if ( m_process )
return;
m_process = new KProcess;
*m_process << command;
connect( m_process, SIGNAL( processExited( KProcess * ) ),
this, SLOT( slotProcessExited( KProcess * ) ) );
#if __FreeBSD__ != 5
if ( comm & Stdout )
connect( m_process, SIGNAL( receivedStdout( KProcess *, char *, int ) ),
this, SLOT( slotReceivedStdout( KProcess *, char *, int ) ) );
if ( comm & Stderr )
connect( m_process, SIGNAL( receivedStderr( KProcess *, char *, int ) ),
this, SLOT( slotReceivedStderr( KProcess *, char *, int ) ) );
// C-style cast because gcc 2.95.4 is buggy and won't allow static_cast
m_process->start( KProcess::NotifyOnExit,
( KProcess::Communication ) comm );
#else
if ( comm & Stdout && comm & Stderr ) {
m_stdoutTempFile = new KTempFile;
m_stdoutTempFile->setAutoDelete( true );
m_stderrTempFile = new KTempFile;
m_stderrTempFile->setAutoDelete( true );
*m_process << "1>" << m_stdoutTempFile->name()
<< "2>" << m_stderrTempFile->name();
} else if ( comm & Stdout ) {
m_stdoutTempFile = new KTempFile;
m_stdoutTempFile->setAutoDelete( true );
*m_process << "1>" << m_stdoutTempFile->name();
} else { // comm & Stderr
m_stderrTempFile = new KTempFile;
m_stderrTempFile->setAutoDelete( true );
*m_process << "2>" << m_stderrTempFile->name();
}
m_process->setUseShell( true );
m_process->start( KProcess::NotifyOnExit );
#endif
}
bool Process::kill( int signo )
{
bool killed = m_process->kill( signo );
if ( killed )
slotProcessExited( m_process );
return killed;
}
void Process::slotReceivedStdout( KProcess *, char *data, int len )
{
emit receivedStdout( this, QString::fromLocal8Bit( data, len ) );
}
void Process::slotReceivedStderr( KProcess *, char *data, int len )
{
emit receivedStderr( this, QString::fromLocal8Bit( data, len ) );
}
void Process::slotReceivedOutput( KProcess *, char *data, int len )
{
m_buffer += QString::fromLocal8Bit( data, len );
}
void Process::slotProcessExited( KProcess *proc )
{
#if __FreeBSD__ == 5
if ( m_stdoutTempFile ) {
const QByteArray data = m_stdoutTempFile->file()->readAll();
emit receivedStdout( this, QString::fromLocal8Bit( data.data(), data.size() ) );
}
if ( m_stderrTempFile ) {
const QByteArray data = m_stderrTempFile->file()->readAll();
emit receivedStderr( this, QString::fromLocal8Bit( data.data(), data.size() ) );
}
delete m_stdoutTempFile;
delete m_stderrTempFile;
#endif
emit finished( this, proc->normalExit() && proc->exitStatus() == 0 );
m_process = 0;
}
ProcessMonitor::ProcessMonitor( QWidget *parent, const char *name )
: KDialogBase( parent, name, true, i18n( "Running command" ),
Cancel, Cancel, true )
{
m_process = new Process;
connect( m_process, SIGNAL( receivedStdout( Process *, const QString & ) ),
this, SLOT( receivedStdout( Process *, const QString & ) ) );
connect( m_process, SIGNAL( receivedStderr( Process *, const QString & ) ),
this, SLOT( receivedStderr( Process *, const QString & ) ) );
connect( m_process, SIGNAL( finished( Process *, bool ) ),
this, SLOT( finished( Process *, bool ) ) );
resize( 500, 300 );
QVBox *mainWidget = makeVBoxMainWidget();
m_outputView = new KTextEdit( mainWidget, "m_outputView" );
m_outputView->setTextFormat( QTextEdit::RichText );
m_outputView->setReadOnly( true );
}
ProcessMonitor::~ProcessMonitor()
{
delete m_process;
}
void ProcessMonitor::slotCancel()
{
reject();
}
void ProcessMonitor::receivedStdout( Process *, const QString &data )
{
m_outputView->append( data.stripWhiteSpace() );
}
void ProcessMonitor::receivedStderr( Process *, const QString &data )
{
m_outputView->append( QString::fromLatin1( "<i>%1</i>" ).arg( data.stripWhiteSpace() ) );
}
void ProcessMonitor::finished( Process *, bool ok )
{
QString msg;
if ( ok )
msg = i18n( "Command finished successfully." );
else
msg = i18n( "There were errors while executing the command. Please "
"check the program's output for details." );
m_outputView->append( QString::fromLatin1( "<p/><p/><b>%1</b>" ).arg( msg ) );
}
#include "process.moc"
// vim:ts=4:sw=4:noet:list
syntax highlighted by Code2HTML, v. 0.9.1