summaryrefslogtreecommitdiff
path: root/library/qprocess.cpp
authorkergoth <kergoth>2002-01-25 22:14:26 (UTC)
committer kergoth <kergoth>2002-01-25 22:14:26 (UTC)
commit15318cad33835e4e2dc620d033e43cd930676cdd (patch) (unidiff)
treec2fa0399a2c47fda8e2cd0092c73a809d17f68eb /library/qprocess.cpp
downloadopie-15318cad33835e4e2dc620d033e43cd930676cdd.zip
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2
Initial revision
Diffstat (limited to 'library/qprocess.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--library/qprocess.cpp654
1 files changed, 654 insertions, 0 deletions
diff --git a/library/qprocess.cpp b/library/qprocess.cpp
new file mode 100644
index 0000000..618c0e0
--- a/dev/null
+++ b/library/qprocess.cpp
@@ -0,0 +1,654 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of QProcess class
5**
6** Created : 20000905
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include <stdio.h>
39#include <stdlib.h>
40
41#include "qprocess.h"
42
43#ifndef QT_NO_PROCESS
44
45#include "qapplication.h"
46
47
48//#define QT_QPROCESS_DEBUG
49
50
51/*!
52 \class QProcess qprocess.h
53
54 \brief The QProcess class is used to start external programs and to
55 communicate with them.
56
57 This is a temporary class. This will be replaced by Qt 3's QProcess class.
58*/
59
60/*!
61 \enum QProcess::Communication
62
63 This enum type defines the communication channels connected to the
64 process.
65
66 \value Stdin Data can be written to the process's standard input.
67
68 \value Stdout Data can be read from the process's standard output.
69
70 \value Stderr Data can be read from the process's standard error.
71
72 \value DupStderr Duplicates standard error to standard output for new
73 processes; i.e. everything that the process writes to standard error, is
74 reported by QProcess on standard output instead. This is especially useful if
75 your application requires that the output on standard output and standard
76 error is read in the same order as the process output it. Please note that
77 this is a binary flag, so if you want to activate this together with standard
78 input, output and error redirection (the default), you have to specify
79 \c{Stdin|Stdout|Stderr|DupStderr} for the setCommunication() call.
80
81 \sa setCommunication() communication()
82*/
83
84/*!
85 Constructs a QProcess object. The \a parent and \a name parameters are passed
86 to the QObject constructor.
87
88 \sa setArguments() addArgument() start()
89*/
90QProcess::QProcess( QObject *parent, const char *name )
91 : QObject( parent, name ), ioRedirection( FALSE ), notifyOnExit( FALSE ),
92 wroteToStdinConnected( FALSE ),
93 readStdoutCalled( FALSE ), readStderrCalled( FALSE ),
94 comms( Stdin|Stdout|Stderr )
95{
96 init();
97}
98
99/*!
100 Constructs a QProcess with \a arg0 as the command to be executed. The
101 \a parent and \a name parameters are passed to the QObject constructor.
102
103 The process is not started. You must call start() or launch()
104 to start the process.
105
106 \sa setArguments() addArgument() start()
107*/
108QProcess::QProcess( const QString& arg0, QObject *parent, const char *name )
109 : QObject( parent, name ), ioRedirection( FALSE ), notifyOnExit( FALSE ),
110 wroteToStdinConnected( FALSE ),
111 readStdoutCalled( FALSE ), readStderrCalled( FALSE ),
112 comms( Stdin|Stdout|Stderr )
113{
114 init();
115 addArgument( arg0 );
116}
117
118/*!
119 Constructs a QProcess with \a args as the arguments of the process. The first
120 element in the list is the command to be executed. The other elements in the
121 list are the arguments to this command. The \a parent and \a name
122 parameters are passed to the QObject constructor.
123
124 The process is not started. You must call start() or launch()
125 to start the process.
126
127 \sa setArguments() addArgument() start()
128*/
129QProcess::QProcess( const QStringList& args, QObject *parent, const char *name )
130 : QObject( parent, name ), ioRedirection( FALSE ), notifyOnExit( FALSE ),
131 wroteToStdinConnected( FALSE ),
132 readStdoutCalled( FALSE ), readStderrCalled( FALSE ),
133 comms( Stdin|Stdout|Stderr )
134{
135 init();
136 setArguments( args );
137}
138
139
140/*!
141 Returns the list of arguments that are set for the process. Arguments can be
142 specified with the constructor or with the functions setArguments() and
143 addArgument().
144
145 \sa setArguments() addArgument()
146*/
147QStringList QProcess::arguments() const
148{
149 return _arguments;
150}
151
152/*!
153 Clears the list of arguments that are set for the process.
154
155 \sa setArguments() addArgument()
156*/
157void QProcess::clearArguments()
158{
159 _arguments.clear();
160}
161
162/*!
163 Sets \a args as the arguments for the process. The first element in the list
164 is the command to be executed. The other elements in the list are the
165 arguments to the command. Any previous arguments are deleted.
166
167 \sa arguments() addArgument()
168*/
169void QProcess::setArguments( const QStringList& args )
170{
171 _arguments = args;
172}
173
174/*!
175 Adds \a arg to the end of the list of arguments.
176
177 The first element in the list of arguments is the command to be
178 executed; the following elements are the arguments to the command.
179
180 \sa arguments() setArguments()
181*/
182void QProcess::addArgument( const QString& arg )
183{
184 _arguments.append( arg );
185}
186
187#ifndef QT_NO_DIR
188/*!
189 Returns the working directory that was set with
190 setWorkingDirectory(), or the current directory if none has been
191 set.
192
193 \sa setWorkingDirectory() QDir::current()
194*/
195QDir QProcess::workingDirectory() const
196{
197 return workingDir;
198}
199
200/*!
201 Sets \a dir as the working directory for a process. This does not affect
202 running processes; only processes that are started afterwards are affected.
203
204 Setting the working directory is especially useful for processes that try to
205 access files with relative filenames.
206
207 \sa workingDirectory() start()
208*/
209void QProcess::setWorkingDirectory( const QDir& dir )
210{
211 workingDir = dir;
212}
213#endif //QT_NO_DIR
214
215/*!
216 Returns the communication required with the process.
217
218 \sa setCommunication()
219*/
220int QProcess::communication() const
221{
222 return comms;
223}
224
225/*!
226 Sets \a commFlags as the communication required with the process.
227
228 \a commFlags is a bitwise OR between the flags defined in \c Communication.
229
230 The default is \c{Stdin|Stdout|Stderr}.
231
232 \sa communication()
233*/
234void QProcess::setCommunication( int commFlags )
235{
236 comms = commFlags;
237}
238
239/*!
240 Returns TRUE if the process has exited normally; otherwise returns
241 FALSE. This implies that this function returns FALSE if the process
242 is still running.
243
244 \sa isRunning() exitStatus() processExited()
245*/
246bool QProcess::normalExit() const
247{
248 // isRunning() has the side effect that it determines the exit status!
249 if ( isRunning() )
250 return FALSE;
251 else
252 return exitNormal;
253}
254
255/*!
256 Returns the exit status of the process or 0 if the process is still
257 running. This function returns immediately and does not wait until
258 the process is finished.
259
260 If normalExit() is FALSE (e.g. if the program was killed or
261 crashed), this function returns 0, so you should check the return
262 value of normalExit() before relying on this value.
263
264 \sa normalExit() processExited()
265*/
266int QProcess::exitStatus() const
267{
268 // isRunning() has the side effect that it determines the exit status!
269 if ( isRunning() )
270 return 0;
271 else
272 return exitStat;
273}
274
275
276/*!
277 Reads the data that the process has written to standard output. When
278 new data is written to standard output, the class emits the signal
279 readyReadStdout().
280
281 If there is no data to read, this function returns a QByteArray of
282 size 0: it does not wait until there is something to read.
283
284 \sa readyReadStdout() readLineStdout() readStderr() writeToStdin()
285*/
286QByteArray QProcess::readStdout()
287{
288 if ( readStdoutCalled ) {
289 return QByteArray();
290 }
291 readStdoutCalled = TRUE;
292
293 QByteArray buf = bufStdout()->copy();
294 consumeBufStdout( -1 ); // consume everything
295
296 readStdoutCalled = FALSE;
297 return buf;
298}
299
300/*!
301 Reads the data that the process has written to standard error. When
302 new data is written to standard error, the class emits the signal
303 readyReadStderr().
304
305 If there is no data to read, this function returns a QByteArray of
306 size 0: it does not wait until there is something to read.
307
308 \sa readyReadStderr() readLineStderr() readStdout() writeToStdin()
309*/
310QByteArray QProcess::readStderr()
311{
312 if ( readStderrCalled ) {
313 return QByteArray();
314 }
315 readStderrCalled = TRUE;
316
317 QByteArray buf = bufStderr()->copy();
318 consumeBufStderr( -1 ); // consume everything
319
320 readStderrCalled = FALSE;
321 return buf;
322}
323
324/*!
325 Returns TRUE if it's possible to read an entire line of text from
326 standard output at this time; otherwise returns FALSE.
327
328 \sa readLineStdout() canReadLineStderr()
329*/
330bool QProcess::canReadLineStdout() const
331{
332 QProcess *that = (QProcess*)this;
333 return that->scanNewline( TRUE, 0 );
334}
335
336/*!
337 Returns TRUE if it's possible to read an entire line of text from
338 standard error at this time; otherwise returns FALSE.
339
340 \sa readLineStderr() canReadLineStdout()
341*/
342bool QProcess::canReadLineStderr() const
343{
344 QProcess *that = (QProcess*)this;
345 return that->scanNewline( FALSE, 0 );
346}
347
348/*!
349 Reads a line of text from standard output, excluding any trailing newline or
350 carriage return characters, and returns it. Returns QString::null if
351 canReadLineStdout() returns FALSE.
352
353 \sa canReadLineStdout() readyReadStdout() readStdout() readLineStderr()
354*/
355QString QProcess::readLineStdout()
356{
357 QByteArray a;
358 QString s;
359 if ( scanNewline( TRUE, &a ) ) {
360 if ( a.isEmpty() )
361 s = "";
362 else
363 s = QString( a );
364 }
365 return s;
366}
367
368/*!
369 Reads a line of text from standard error, excluding any trailing newline or
370 carriage return characters and returns it. Returns QString::null if
371 canReadLineStderr() returns FALSE.
372
373 \sa canReadLineStderr() readyReadStderr() readStderr() readLineStdout()
374*/
375QString QProcess::readLineStderr()
376{
377 QByteArray a;
378 QString s;
379 if ( scanNewline( FALSE, &a ) ) {
380 if ( a.isEmpty() )
381 s = "";
382 else
383 s = QString( a );
384 }
385 return s;
386}
387
388/*!
389 This private function scans for any occurrence of \n or \r\n in the
390 buffer \e buf. It stores the text in the byte array \a store if it is
391 non-null.
392*/
393bool QProcess::scanNewline( bool stdOut, QByteArray *store )
394{
395 QByteArray *buf;
396 if ( stdOut )
397 buf = bufStdout();
398 else
399 buf = bufStderr();
400 uint n = buf->size();
401 uint i;
402 for ( i=0; i<n; i++ ) {
403 if ( buf->at(i) == '\n' ) {
404 break;
405 }
406 }
407 if ( i >= n )
408 return FALSE;
409
410 if ( store ) {
411 uint lineLength = i;
412 if ( lineLength>0 && buf->at(lineLength-1) == '\r' )
413 lineLength--; // (if there are two \r, let one stay)
414 store->resize( lineLength );
415 memcpy( store->data(), buf->data(), lineLength );
416 if ( stdOut )
417 consumeBufStdout( i+1 );
418 else
419 consumeBufStderr( i+1 );
420 }
421 return TRUE;
422}
423
424/*!
425 \fn void QProcess::launchFinished()
426
427 This signal is emitted when the process was started with launch().
428 If the start was successful, this signal is emitted after all the
429 data has been written to standard input. If the start failed, then
430 this signal is emitted immediately.
431
432 \sa launch() QObject::deleteLater()
433*/
434
435/*!
436 Runs the process and writes the data \a buf to the process's standard input.
437 If all the data is written to standard input, standard input is
438 closed. The command is searched for in the path for executable programs;
439 you can also use an absolute path in the command itself.
440
441 If \a env is null, then the process is started with the same environment as
442 the starting process. If \a env is non-null, then the values in the
443 stringlist are interpreted as environment setttings of the form \c
444 {key=value} and the process is started with these environment settings. For
445 convenience, there is a small exception to this rule under Unix: if \a env
446 does not contain any settings for the environment variable \c
447 LD_LIBRARY_PATH, then this variable is inherited from the starting process.
448
449 Returns TRUE if the process could be started; otherwise returns FALSE.
450
451 Note that you should not use the slots writeToStdin() and closeStdin() on
452 processes started with launch(), since the result is not well-defined. If you
453 need these slots, use start() instead.
454
455 The process may or may not read the \a buf data sent to its standard
456 input.
457
458 You can call this function even when a process that was started with
459 this instance is still running. Be aware that if you do this the
460 standard input of the process that was launched first will be
461 closed, with any pending data being deleted, and the process will be
462 left to run out of your control. Similarly, if the process could not
463 be started the standard input will be closed and the pending data
464 deleted. (On operating systems that have zombie processes, Qt will
465 also wait() on the old process.)
466
467 The object emits the signal launchFinished() when this function
468 call is finished. If the start was successful, this signal is
469 emitted after all the data has been written to standard input. If
470 the start failed, then this signal is emitted immediately.
471
472 \sa start() launchFinished();
473*/
474bool QProcess::launch( const QByteArray& buf, QStringList *env )
475{
476 if ( start( env ) ) {
477 if ( !buf.isEmpty() ) {
478 connect( this, SIGNAL(wroteToStdin()),
479 this, SLOT(closeStdinLaunch()) );
480 writeToStdin( buf );
481 } else {
482 closeStdin();
483 emit launchFinished();
484 }
485 return TRUE;
486 } else {
487 emit launchFinished();
488 return FALSE;
489 }
490}
491
492/*! \overload
493
494 The data \a buf is written to standard input with writeToStdin()
495 using the QString::local8Bit() representation of the strings.
496*/
497bool QProcess::launch( const QString& buf, QStringList *env )
498{
499 if ( start( env ) ) {
500 if ( !buf.isEmpty() ) {
501 connect( this, SIGNAL(wroteToStdin()),
502 this, SLOT(closeStdinLaunch()) );
503 writeToStdin( buf );
504 } else {
505 closeStdin();
506 emit launchFinished();
507 }
508 return TRUE;
509 } else {
510 emit launchFinished();
511 return FALSE;
512 }
513}
514
515/*!
516 This private slot is used by the launch() functions to close standard input.
517*/
518void QProcess::closeStdinLaunch()
519{
520 disconnect( this, SIGNAL(wroteToStdin()),
521 this, SLOT(closeStdinLaunch()) );
522 closeStdin();
523 emit launchFinished();
524}
525
526
527/*!
528 \fn void QProcess::readyReadStdout()
529
530 This signal is emitted when the process has written data to standard output.
531 You can read the data with readStdout().
532
533 Note that this signal is only emitted when there is new data and not
534 when there is old, but unread data. In the slot connected to this signal, you
535 should always read everything that is available at that moment to make sure
536 that you don't lose any data.
537
538 \sa readStdout() readLineStdout() readyReadStderr()
539*/
540/*!
541 \fn void QProcess::readyReadStderr()
542
543 This signal is emitted when the process has written data to standard error.
544 You can read the data with readStderr().
545
546 Note that this signal is only emitted when there is new data and not
547 when there is old, but unread data. In the slot connected to this signal, you
548 should always read everything that is available at that moment to make sure
549 that you don't lose any data.
550
551 \sa readStderr() readLineStderr() readyReadStdout()
552*/
553/*!
554 \fn void QProcess::processExited()
555
556 This signal is emitted when the process has exited.
557
558 \sa isRunning() normalExit() exitStatus() start() launch()
559*/
560/*!
561 \fn void QProcess::wroteToStdin()
562
563 This signal is emitted if the data sent to standard input (via
564 writeToStdin()) was actually written to the process. This does not
565 imply that the process really read the data, since this class only detects
566 when it was able to write the data to the operating system. But it is now
567 safe to close standard input without losing pending data.
568
569 \sa writeToStdin() closeStdin()
570*/
571
572
573/*! \overload
574
575 The string \a buf is handled as text using
576 the QString::local8Bit() representation.
577*/
578void QProcess::writeToStdin( const QString& buf )
579{
580 QByteArray tmp = buf.local8Bit();
581 tmp.resize( buf.length() );
582 writeToStdin( tmp );
583}
584
585
586/*
587 * Under Windows the implementation is not so nice: it is not that easy to
588 * detect when one of the signals should be emitted; therefore there are some
589 * timers that query the information.
590 * To keep it a little efficient, use the timers only when they are needed.
591 * They are needed, if you are interested in the signals. So use
592 * connectNotify() and disconnectNotify() to keep track of your interest.
593 */
594/*! \reimp
595*/
596void QProcess::connectNotify( const char * signal )
597{
598#if defined(QT_QPROCESS_DEBUG)
599 qDebug( "QProcess::connectNotify(): signal %s has been connected", signal );
600#endif
601 if ( !ioRedirection )
602 if ( qstrcmp( signal, SIGNAL(readyReadStdout()) )==0 ||
603 qstrcmp( signal, SIGNAL(readyReadStderr()) )==0
604 ) {
605#if defined(QT_QPROCESS_DEBUG)
606 qDebug( "QProcess::connectNotify(): set ioRedirection to TRUE" );
607#endif
608 setIoRedirection( TRUE );
609 return;
610 }
611 if ( !notifyOnExit && qstrcmp( signal, SIGNAL(processExited()) )==0 ) {
612#if defined(QT_QPROCESS_DEBUG)
613 qDebug( "QProcess::connectNotify(): set notifyOnExit to TRUE" );
614#endif
615 setNotifyOnExit( TRUE );
616 return;
617 }
618 if ( !wroteToStdinConnected && qstrcmp( signal, SIGNAL(wroteToStdin()) )==0 ) {
619#if defined(QT_QPROCESS_DEBUG)
620 qDebug( "QProcess::connectNotify(): set wroteToStdinConnected to TRUE" );
621#endif
622 setWroteStdinConnected( TRUE );
623 return;
624 }
625}
626
627/*! \reimp
628*/
629void QProcess::disconnectNotify( const char * )
630{
631 if ( ioRedirection &&
632 receivers( SIGNAL(readyReadStdout()) ) ==0 &&
633 receivers( SIGNAL(readyReadStderr()) ) ==0
634 ) {
635#if defined(QT_QPROCESS_DEBUG)
636 qDebug( "QProcess::disconnectNotify(): set ioRedirection to FALSE" );
637#endif
638 setIoRedirection( FALSE );
639 }
640 if ( notifyOnExit && receivers( SIGNAL(processExited()) ) == 0 ) {
641#if defined(QT_QPROCESS_DEBUG)
642 qDebug( "QProcess::disconnectNotify(): set notifyOnExit to FALSE" );
643#endif
644 setNotifyOnExit( FALSE );
645 }
646 if ( wroteToStdinConnected && receivers( SIGNAL(wroteToStdin()) ) == 0 ) {
647#if defined(QT_QPROCESS_DEBUG)
648 qDebug( "QProcess::disconnectNotify(): set wroteToStdinConnected to FALSE" );
649#endif
650 setWroteStdinConnected( FALSE );
651 }
652}
653
654#endif // QT_NO_PROCESS