/* * process.cc * * Copyright (c) 2003 Frerich Raabe * * 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 #include #if __FreeBSD__ == 5 # include #endif #include #if __FreeBSD__ == 5 # include #endif #include 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( "%1" ).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( "

%1" ).arg( msg ) ); } #include "process.moc" // vim:ts=4:sw=4:noet:list