summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/qcleanuphandler_p.h51
-rw-r--r--core/launcher/qprocess.cpp654
-rw-r--r--core/launcher/qprocess.h174
-rw-r--r--core/launcher/qprocess_unix.cpp1158
-rw-r--r--import.log0
-rw-r--r--library/fileselector_p.h56
-rw-r--r--library/mediaplayerplugininterface.h110
-rw-r--r--pics/cards/card_back0001_small.pngbin0 -> 736 bytes
-rw-r--r--pics/cards/card_back0002_small.pngbin0 -> 1317 bytes
-rw-r--r--pics/cards/card_back0003_small.pngbin0 -> 1128 bytes
-rw-r--r--pics/cards/card_back0004_small.pngbin0 -> 1375 bytes
-rw-r--r--pics/cards/card_back0005_small.pngbin0 -> 1050 bytes
-rw-r--r--pics/cards/card_chars_small.pngbin0 -> 225 bytes
-rw-r--r--pics/cards/card_face_small.pngbin0 -> 265 bytes
-rw-r--r--pics/cards/card_suits_small.pngbin0 -> 185 bytes
15 files changed, 2203 insertions, 0 deletions
diff --git a/core/launcher/qcleanuphandler_p.h b/core/launcher/qcleanuphandler_p.h
new file mode 100644
index 0000000..d8cddac
--- a/dev/null
+++ b/core/launcher/qcleanuphandler_p.h
@@ -0,0 +1,51 @@
1#ifndef QCLEANUPHANDLER_H
2#define QCLEANUPHANDLER_H
3
4#ifndef QT_H
5#include <qlist.h>
6#endif // QT_H
7
8template<class Type>
9class Q_EXPORT QCleanupHandler
10{
11public:
12 QCleanupHandler() : cleanupObjects( 0 ) {}
13 ~QCleanupHandler() { clear(); }
14
15 Type* add( Type **object ) {
16 if ( !cleanupObjects )
17 cleanupObjects = new QList<Type*>;
18 cleanupObjects->insert( 0, object );
19 return *object;
20 }
21
22 void remove( Type **object ) {
23 if ( !cleanupObjects )
24 return;
25 if ( cleanupObjects->findRef( object ) >= 0 )
26 (void) cleanupObjects->take();
27 }
28
29 bool isEmpty() const {
30 return cleanupObjects ? cleanupObjects->isEmpty() : TRUE;
31 }
32
33 void clear() {
34 if ( !cleanupObjects )
35 return;
36 QListIterator<Type*> it( *cleanupObjects );
37 Type **object;
38 while ( ( object = it.current() ) ) {
39 delete *object;
40 *object = 0;
41 cleanupObjects->remove( object );
42 }
43 delete cleanupObjects;
44 cleanupObjects = 0;
45 }
46
47private:
48 QList<Type*> *cleanupObjects;
49};
50
51#endif //QCLEANUPHANDLER_H
diff --git a/core/launcher/qprocess.cpp b/core/launcher/qprocess.cpp
new file mode 100644
index 0000000..618c0e0
--- a/dev/null
+++ b/core/launcher/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
diff --git a/core/launcher/qprocess.h b/core/launcher/qprocess.h
new file mode 100644
index 0000000..306e659
--- a/dev/null
+++ b/core/launcher/qprocess.h
@@ -0,0 +1,174 @@
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#ifndef QPROCESS_H
39#define QPROCESS_H
40
41#ifndef QT_H
42#include "qobject.h"
43#include "qstringlist.h"
44#include "qdir.h"
45#endif // QT_H
46
47#ifndef QT_NO_PROCESS
48
49class QProcessPrivate;
50
51
52class Q_EXPORT QProcess : public QObject
53{
54 Q_OBJECT
55public:
56 QProcess( QObject *parent=0, const char *name=0 );
57 QProcess( const QString& arg0, QObject *parent=0, const char *name=0 );
58 QProcess( const QStringList& args, QObject *parent=0, const char *name=0 );
59 ~QProcess();
60
61 // set and get the arguments and working directory
62 QStringList arguments() const;
63 void clearArguments();
64 virtual void setArguments( const QStringList& args );
65 virtual void addArgument( const QString& arg );
66#ifndef QT_NO_DIR
67 QDir workingDirectory() const;
68 virtual void setWorkingDirectory( const QDir& dir );
69#endif
70
71 // set and get the comms wanted
72 enum Communication { Stdin=0x01, Stdout=0x02, Stderr=0x04, DupStderr=0x08 };
73 void setCommunication( int c );
74 int communication() const;
75
76 // start the execution
77 virtual bool start( QStringList *env=0 );
78 virtual bool launch( const QString& buf, QStringList *env=0 );
79 virtual bool launch( const QByteArray& buf, QStringList *env=0 );
80
81 // inquire the status
82 bool isRunning() const;
83 bool normalExit() const;
84 int exitStatus() const;
85
86 // reading
87 virtual QByteArray readStdout();
88 virtual QByteArray readStderr();
89 bool canReadLineStdout() const;
90 bool canReadLineStderr() const;
91 virtual QString readLineStdout();
92 virtual QString readLineStderr();
93
94 // get platform dependent process information
95#if defined(Q_OS_WIN32)
96 typedef void* PID;
97#else
98 typedef long Q_LONG;
99 typedef Q_LONG PID;
100#endif
101 PID processIdentifier();
102
103 void flushStdin();
104
105signals:
106 void readyReadStdout();
107 void readyReadStderr();
108 void processExited();
109 void wroteToStdin();
110 void launchFinished();
111
112public slots:
113 // end the execution
114 void tryTerminate() const;
115 void kill() const;
116
117 // input
118 virtual void writeToStdin( const QByteArray& buf );
119 virtual void writeToStdin( const QString& buf );
120 virtual void closeStdin();
121
122protected: // ### or private?
123 void connectNotify( const char * signal );
124 void disconnectNotify( const char * signal );
125private:
126 void setIoRedirection( bool value );
127 void setNotifyOnExit( bool value );
128 void setWroteStdinConnected( bool value );
129
130 void init();
131 void reset();
132#if defined(Q_OS_WIN32)
133 uint readStddev( HANDLE dev, char *buf, uint bytes );
134#endif
135 bool scanNewline( bool stdOut, QByteArray *store );
136
137 QByteArray* bufStdout();
138 QByteArray* bufStderr();
139 void consumeBufStdout( int consume );
140 void consumeBufStderr( int consume );
141
142private slots:
143 void socketRead( int fd );
144 void socketWrite( int fd );
145 void timeout();
146 void closeStdinLaunch();
147
148private:
149 QProcessPrivate *d;
150#ifndef QT_NO_DIR
151 QDir workingDir;
152#endif
153 QStringList _arguments;
154
155 int exitStat; // exit status
156 bool exitNormal; // normal exit?
157 bool ioRedirection; // automatically set be (dis)connectNotify
158 bool notifyOnExit; // automatically set be (dis)connectNotify
159 bool wroteToStdinConnected; // automatically set be (dis)connectNotify
160
161 bool readStdoutCalled;
162 bool readStderrCalled;
163 int comms;
164
165 friend class QProcessPrivate;
166#if defined(Q_OS_UNIX) || defined(_OS_UNIX) || defined(UNIX)
167 friend class QProcessManager;
168 friend class QProc;
169#endif
170};
171
172#endif // QT_NO_PROCESS
173
174#endif // QPROCESS_H
diff --git a/core/launcher/qprocess_unix.cpp b/core/launcher/qprocess_unix.cpp
new file mode 100644
index 0000000..75f0f0c
--- a/dev/null
+++ b/core/launcher/qprocess_unix.cpp
@@ -0,0 +1,1158 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of QProcess class for Unix
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 "qplatformdefs.h"
39
40// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
41#if defined(connect)
42#undef connect
43#endif
44
45#include "qprocess.h"
46
47#ifndef QT_NO_PROCESS
48
49#include "qapplication.h"
50#include "qqueue.h"
51#include "qlist.h"
52#include "qsocketnotifier.h"
53#include "qtimer.h"
54#include "qregexp.h"
55
56#include "qcleanuphandler_p.h"
57
58#include <stdlib.h>
59
60// ### FOR Qt 2.3 compat
61#include <unistd.h>
62#include <signal.h>
63#include <sys/socket.h>
64#include <sys/ioctl.h>
65#include <sys/wait.h>
66#include <sys/fcntl.h>
67
68#include <errno.h>
69
70#ifdef __MIPSEL__
71# ifndef SOCK_DGRAM
72# define SOCK_DGRAM 1
73# endif
74# ifndef SOCK_STREAM
75# define SOCK_STREAM 2
76# endif
77#endif
78
79//#define QT_QPROCESS_DEBUG
80
81
82#ifdef Q_C_CALLBACKS
83extern "C" {
84#endif // Q_C_CALLBACKS
85
86#define QT_SIGNAL_RETTYPE void
87#define QT_SIGNAL_ARGS int
88#define QT_SIGNAL_IGNORE SIG_IGN
89
90 QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS);
91
92#ifdef Q_C_CALLBACKS
93}
94#endif // Q_C_CALLBACKS
95
96
97class QProc;
98class QProcessManager;
99class QProcessPrivate
100{
101public:
102 QProcessPrivate();
103 ~QProcessPrivate();
104
105 void closeOpenSocketsForChild();
106 void newProc( pid_t pid, QProcess *process );
107
108 QByteArray bufStdout;
109 QByteArray bufStderr;
110
111 QQueue<QByteArray> stdinBuf;
112
113 QSocketNotifier *notifierStdin;
114 QSocketNotifier *notifierStdout;
115 QSocketNotifier *notifierStderr;
116
117 ssize_t stdinBufRead;
118 QProc *proc;
119
120 bool exitValuesCalculated;
121 bool socketReadCalled;
122
123 static QProcessManager *procManager;
124};
125
126
127/***********************************************************************
128 *
129 * QProc
130 *
131 **********************************************************************/
132/*
133 The class QProcess does not necessarily map exactly to the running
134 child processes: if the process is finished, the QProcess class may still be
135 there; furthermore a user can use QProcess to start more than one process.
136
137 The helper-class QProc has the semantics that one instance of this class maps
138 directly to a running child process.
139*/
140class QProc
141{
142public:
143 QProc( pid_t p, QProcess *proc=0 ) : pid(p), process(proc)
144 {
145#if defined(QT_QPROCESS_DEBUG)
146 qDebug( "QProc: Constructor for pid %d and QProcess %p", pid, process );
147#endif
148 socketStdin = 0;
149 socketStdout = 0;
150 socketStderr = 0;
151 }
152 ~QProc()
153 {
154#if defined(QT_QPROCESS_DEBUG)
155 qDebug( "QProc: Destructor for pid %d and QProcess %p", pid, process );
156#endif
157 if ( process != 0 ) {
158 if ( process->d->notifierStdin )
159 process->d->notifierStdin->setEnabled( FALSE );
160 if ( process->d->notifierStdout )
161 process->d->notifierStdout->setEnabled( FALSE );
162 if ( process->d->notifierStderr )
163 process->d->notifierStderr->setEnabled( FALSE );
164 process->d->proc = 0;
165 }
166 if( socketStdin != 0 )
167 ::close( socketStdin );
168 // ### close these sockets even on parent exit or is it better only on
169 // sigchld (but what do I have to do with them on exit then)?
170 if( socketStdout != 0 )
171 ::close( socketStdout );
172 if( socketStderr != 0 )
173 ::close( socketStderr );
174 }
175
176 pid_t pid;
177 int socketStdin;
178 int socketStdout;
179 int socketStderr;
180 QProcess *process;
181};
182
183/***********************************************************************
184 *
185 * QProcessManager
186 *
187 **********************************************************************/
188class QProcessManager : public QObject
189{
190 Q_OBJECT
191
192public:
193 QProcessManager();
194 ~QProcessManager();
195
196 void append( QProc *p );
197 void remove( QProc *p );
198
199 void cleanup();
200
201public slots:
202 void removeMe();
203 void sigchldHnd( int );
204
205public:
206 struct sigaction oldactChld;
207 struct sigaction oldactPipe;
208 QList<QProc> *procList;
209 int sigchldFd[2];
210};
211
212QCleanupHandler<QProcessManager> qprocess_cleanup_procmanager;
213
214QProcessManager::QProcessManager()
215{
216 procList = new QList<QProc>;
217 procList->setAutoDelete( TRUE );
218
219 // The SIGCHLD handler writes to a socket to tell the manager that
220 // something happened. This is done to get the processing in sync with the
221 // event reporting.
222 if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) {
223 sigchldFd[0] = 0;
224 sigchldFd[1] = 0;
225 } else {
226#if defined(QT_QPROCESS_DEBUG)
227 qDebug( "QProcessManager: install socket notifier (%d)", sigchldFd[1] );
228#endif
229 QSocketNotifier *sn = new QSocketNotifier( sigchldFd[1],
230 QSocketNotifier::Read, this );
231 connect( sn, SIGNAL(activated(int)),
232 this, SLOT(sigchldHnd(int)) );
233 sn->setEnabled( TRUE );
234 }
235
236 // install a SIGCHLD handler and ignore SIGPIPE
237 struct sigaction act;
238
239#if defined(QT_QPROCESS_DEBUG)
240 qDebug( "QProcessManager: install a SIGCHLD handler" );
241#endif
242 act.sa_handler = qt_C_sigchldHnd;
243 sigemptyset( &(act.sa_mask) );
244 sigaddset( &(act.sa_mask), SIGCHLD );
245 act.sa_flags = SA_NOCLDSTOP;
246#if defined(SA_RESTART)
247 act.sa_flags |= SA_RESTART;
248#endif
249 if ( sigaction( SIGCHLD, &act, &oldactChld ) != 0 )
250 qWarning( "Error installing SIGCHLD handler" );
251
252#if defined(QT_QPROCESS_DEBUG)
253 qDebug( "QProcessManager: install a SIGPIPE handler (SIG_IGN)" );
254#endif
255 act.sa_handler = QT_SIGNAL_IGNORE;
256 sigemptyset( &(act.sa_mask) );
257 sigaddset( &(act.sa_mask), SIGPIPE );
258 act.sa_flags = 0;
259 if ( sigaction( SIGPIPE, &act, &oldactPipe ) != 0 )
260 qWarning( "Error installing SIGPIPE handler" );
261}
262
263QProcessManager::~QProcessManager()
264{
265 delete procList;
266
267 if ( sigchldFd[0] != 0 )
268 ::close( sigchldFd[0] );
269 if ( sigchldFd[1] != 0 )
270 ::close( sigchldFd[1] );
271
272 // restore SIGCHLD handler
273#if defined(QT_QPROCESS_DEBUG)
274 qDebug( "QProcessManager: restore old sigchild handler" );
275#endif
276 if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 )
277 qWarning( "Error restoring SIGCHLD handler" );
278
279#if defined(QT_QPROCESS_DEBUG)
280 qDebug( "QProcessManager: restore old sigpipe handler" );
281#endif
282 if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 )
283 qWarning( "Error restoring SIGPIPE handler" );
284}
285
286void QProcessManager::append( QProc *p )
287{
288 procList->append( p );
289#if defined(QT_QPROCESS_DEBUG)
290 qDebug( "QProcessManager: append process (procList.count(): %d)", procList->count() );
291#endif
292}
293
294void QProcessManager::remove( QProc *p )
295{
296 procList->remove( p );
297#if defined(QT_QPROCESS_DEBUG)
298 qDebug( "QProcessManager: remove process (procList.count(): %d)", procList->count() );
299#endif
300 cleanup();
301}
302
303void QProcessManager::cleanup()
304{
305 if ( procList->count() == 0 ) {
306 QTimer::singleShot( 0, this, SLOT(removeMe()) );
307 }
308}
309
310void QProcessManager::removeMe()
311{
312 if ( procList->count() == 0 ) {
313 qprocess_cleanup_procmanager.remove( &QProcessPrivate::procManager );
314 QProcessPrivate::procManager = 0;
315 delete this;
316 }
317}
318
319void QProcessManager::sigchldHnd( int fd )
320{
321 char tmp;
322 ::read( fd, &tmp, sizeof(tmp) );
323#if defined(QT_QPROCESS_DEBUG)
324 qDebug( "QProcessManager::sigchldHnd()" );
325#endif
326 QProc *proc;
327 QProcess *process;
328 bool removeProc;
329 proc = procList->first();
330 while ( proc != 0 ) {
331 removeProc = FALSE;
332 process = proc->process;
333 if ( process != 0 ) {
334 if ( !process->isRunning() ) {
335#if defined(QT_QPROCESS_DEBUG)
336 qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess available)", proc->pid );
337#endif
338 // read pending data
339 int nbytes = 0;
340 if ( ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
341#if defined(QT_QPROCESS_DEBUG)
342 qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stdout", proc->pid, nbytes );
343#endif
344 process->socketRead( proc->socketStdout );
345 }
346 nbytes = 0;
347 if ( ::ioctl(proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
348#if defined(QT_QPROCESS_DEBUG)
349 qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stderr", proc->pid, nbytes );
350#endif
351 process->socketRead( proc->socketStderr );
352 }
353
354 if ( process->notifyOnExit )
355 emit process->processExited();
356
357 removeProc = TRUE;
358 }
359 } else {
360 int status;
361 if ( ::waitpid( proc->pid, &status, WNOHANG ) == proc->pid ) {
362#if defined(QT_QPROCESS_DEBUG)
363 qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess not available)", proc->pid );
364#endif
365 removeProc = TRUE;
366 }
367 }
368 if ( removeProc ) {
369 QProc *oldproc = proc;
370 proc = procList->next();
371 remove( oldproc );
372 } else {
373 proc = procList->next();
374 }
375 }
376}
377
378#include "qprocess_unix.moc"
379
380
381/***********************************************************************
382 *
383 * QProcessPrivate
384 *
385 **********************************************************************/
386QProcessManager *QProcessPrivate::procManager = 0;
387
388QProcessPrivate::QProcessPrivate()
389{
390#if defined(QT_QPROCESS_DEBUG)
391 qDebug( "QProcessPrivate: Constructor" );
392#endif
393 stdinBufRead = 0;
394
395 notifierStdin = 0;
396 notifierStdout = 0;
397 notifierStderr = 0;
398
399 exitValuesCalculated = FALSE;
400 socketReadCalled = FALSE;
401
402 proc = 0;
403}
404
405QProcessPrivate::~QProcessPrivate()
406{
407#if defined(QT_QPROCESS_DEBUG)
408 qDebug( "QProcessPrivate: Destructor" );
409#endif
410
411 if ( proc != 0 ) {
412 if ( proc->socketStdin != 0 ) {
413 ::close( proc->socketStdin );
414 proc->socketStdin = 0;
415 }
416 proc->process = 0;
417 }
418
419 while ( !stdinBuf.isEmpty() ) {
420 delete stdinBuf.dequeue();
421 }
422 delete notifierStdin;
423 delete notifierStdout;
424 delete notifierStderr;
425}
426
427/*
428 Closes all open sockets in the child process that are not needed by the child
429 process. Otherwise one child may have an open socket on standard input, etc.
430 of another child.
431*/
432void QProcessPrivate::closeOpenSocketsForChild()
433{
434 if ( procManager != 0 ) {
435 if ( procManager->sigchldFd[0] != 0 )
436 ::close( procManager->sigchldFd[0] );
437 if ( procManager->sigchldFd[1] != 0 )
438 ::close( procManager->sigchldFd[1] );
439
440 // close also the sockets from other QProcess instances
441 QProc *proc;
442 for ( proc=procManager->procList->first(); proc!=0; proc=procManager->procList->next() ) {
443 ::close( proc->socketStdin );
444 ::close( proc->socketStdout );
445 ::close( proc->socketStderr );
446 }
447 }
448}
449
450void QProcessPrivate::newProc( pid_t pid, QProcess *process )
451{
452 proc = new QProc( pid, process );
453 if ( procManager == 0 ) {
454 procManager = new QProcessManager;
455 qprocess_cleanup_procmanager.add( &procManager );
456 }
457 // the QProcessManager takes care of deleting the QProc instances
458 procManager->append( proc );
459}
460
461/***********************************************************************
462 *
463 * sigchld handler callback
464 *
465 **********************************************************************/
466QT_SIGNAL_RETTYPE qt_C_sigchldHnd( QT_SIGNAL_ARGS )
467{
468 if ( QProcessPrivate::procManager == 0 )
469 return;
470 if ( QProcessPrivate::procManager->sigchldFd[0] == 0 )
471 return;
472
473 char a = 1;
474 ::write( QProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );
475}
476
477
478/***********************************************************************
479 *
480 * QProcess
481 *
482 **********************************************************************/
483/*!
484 This private class does basic initialization.
485*/
486void QProcess::init()
487{
488 d = new QProcessPrivate();
489 exitStat = 0;
490 exitNormal = FALSE;
491}
492
493/*!
494 This private class resets the process variables, etc. so that it can be used
495 for another process to start.
496*/
497void QProcess::reset()
498{
499 delete d;
500 d = new QProcessPrivate();
501 exitStat = 0;
502 exitNormal = FALSE;
503 d->bufStdout.resize( 0 );
504 d->bufStderr.resize( 0 );
505}
506
507QByteArray* QProcess::bufStdout()
508{
509 if ( d->proc && d->proc->socketStdout ) {
510 // ### can this cause a blocking behaviour (maybe do a ioctl() to see
511 // if data is available)?
512 socketRead( d->proc->socketStdout );
513 }
514 return &d->bufStdout;
515}
516
517QByteArray* QProcess::bufStderr()
518{
519 if ( d->proc && d->proc->socketStderr ) {
520 // ### can this cause a blocking behaviour (maybe do a ioctl() to see
521 // if data is available)?
522 socketRead( d->proc->socketStderr );
523 }
524 return &d->bufStderr;
525}
526
527void QProcess::consumeBufStdout( int consume )
528{
529 uint n = d->bufStdout.size();
530 if ( consume==-1 || (uint)consume >= n ) {
531 d->bufStdout.resize( 0 );
532 } else {
533 QByteArray tmp( n - consume );
534 memcpy( tmp.data(), d->bufStdout.data()+consume, n-consume );
535 d->bufStdout = tmp;
536 }
537}
538
539void QProcess::consumeBufStderr( int consume )
540{
541 uint n = d->bufStderr.size();
542 if ( consume==-1 || (uint)consume >= n ) {
543 d->bufStderr.resize( 0 );
544 } else {
545 QByteArray tmp( n - consume );
546 memcpy( tmp.data(), d->bufStderr.data()+consume, n-consume );
547 d->bufStderr = tmp;
548 }
549}
550
551/*!
552 Destroys the class.
553
554 If the process is running, it is NOT terminated! Standard input, standard
555 output and standard error of the process are closed.
556
557 You can connect the destroyed() signal to the kill() slot, if you want the
558 process to be terminated automatically when the class is destroyed.
559
560 \sa tryTerminate() kill()
561*/
562QProcess::~QProcess()
563{
564 delete d;
565}
566
567/*!
568 Tries to run a process for the command and arguments that were specified with
569 setArguments(), addArgument() or that were specified in the constructor. The
570 command is searched in the path for executable programs; you can also use an
571 absolute path to the command.
572
573 If \a env is null, then the process is started with the same environment as
574 the starting process. If \a env is non-null, then the values in the
575 stringlist are interpreted as environment setttings of the form \c
576 {key=value} and the process is started in these environment settings. For
577 convenience, there is a small exception to this rule: under Unix, if \a env
578 does not contain any settings for the environment variable \c
579 LD_LIBRARY_PATH, then this variable is inherited from the starting process;
580 under Windows the same applies for the enverionment varialbe \c PATH.
581
582 Returns TRUE if the process could be started, otherwise FALSE.
583
584 You can write data to standard input of the process with
585 writeToStdin(), you can close standard input with closeStdin() and you can
586 terminate the process tryTerminate() resp. kill().
587
588 You can call this function even when there already is a running
589 process in this object. In this case, QProcess closes standard input
590 of the old process and deletes pending data, i.e., you loose all
591 control over that process, but the process is not terminated. This applies
592 also if the process could not be started. (On operating systems that have
593 zombie processes, Qt will also wait() on the old process.)
594
595 \sa launch() closeStdin()
596*/
597bool QProcess::start( QStringList *env )
598{
599#if defined(QT_QPROCESS_DEBUG)
600 qDebug( "QProcess::start()" );
601#endif
602 reset();
603
604 int sStdin[2];
605 int sStdout[2];
606 int sStderr[2];
607
608 // open sockets for piping
609 if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) {
610 return FALSE;
611 }
612 if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) {
613 return FALSE;
614 }
615 if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) {
616 return FALSE;
617 }
618
619 // the following pipe is only used to determine if the process could be
620 // started
621 int fd[2];
622 if ( pipe( fd ) < 0 ) {
623 // non critical error, go on
624 fd[0] = 0;
625 fd[1] = 0;
626 }
627
628 // construct the arguments for exec
629 QCString *arglistQ = new QCString[ _arguments.count() + 1 ];
630 const char** arglist = new const char*[ _arguments.count() + 1 ];
631 int i = 0;
632 for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) {
633 arglistQ[i] = (*it).local8Bit();
634 arglist[i] = arglistQ[i];
635#if defined(QT_QPROCESS_DEBUG)
636 qDebug( "QProcess::start(): arg %d = %s", i, arglist[i] );
637#endif
638 i++;
639 }
640 arglist[i] = 0;
641
642 // Must make sure signal handlers are installed before exec'ing
643 // in case the process exits quickly.
644 if ( d->procManager == 0 ) {
645 d->procManager = new QProcessManager;
646 qprocess_cleanup_procmanager.add( &d->procManager );
647 }
648
649 // fork and exec
650 QApplication::flushX();
651 pid_t pid = fork();
652 if ( pid == 0 ) {
653 // child
654 d->closeOpenSocketsForChild();
655 if ( comms & Stdin ) {
656 ::close( sStdin[1] );
657 ::dup2( sStdin[0], STDIN_FILENO );
658 }
659 if ( comms & Stdout ) {
660 ::close( sStdout[0] );
661 ::dup2( sStdout[1], STDOUT_FILENO );
662 }
663 if ( comms & Stderr ) {
664 ::close( sStderr[0] );
665 ::dup2( sStderr[1], STDERR_FILENO );
666 }
667 if ( comms & DupStderr ) {
668 ::dup2( STDOUT_FILENO, STDERR_FILENO );
669 }
670#ifndef QT_NO_DIR
671 ::chdir( workingDir.absPath().latin1() );
672#endif
673 if ( fd[0] )
674 ::close( fd[0] );
675 if ( fd[1] )
676 ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows sucess
677
678 if ( env == 0 ) { // inherit environment and start process
679 ::execvp( arglist[0], (char*const*)arglist ); // ### cast not nice
680 } else { // start process with environment settins as specified in env
681 // construct the environment for exec
682 int numEntries = env->count();
683 bool setLibraryPath =
684 env->grep( QRegExp( "^LD_LIBRARY_PATH=" ) ).isEmpty() &&
685 getenv( "LD_LIBRARY_PATH" ) != 0;
686 if ( setLibraryPath )
687 numEntries++;
688 QCString *envlistQ = new QCString[ numEntries + 1 ];
689 const char** envlist = new const char*[ numEntries + 1 ];
690 int i = 0;
691 if ( setLibraryPath ) {
692 envlistQ[i] = QString( "LD_LIBRARY_PATH=%1" ).arg( getenv( "LD_LIBRARY_PATH" ) ).local8Bit();
693 envlist[i] = envlistQ[i];
694 i++;
695 }
696 for ( QStringList::Iterator it = env->begin(); it != env->end(); ++it ) {
697 envlistQ[i] = (*it).local8Bit();
698 envlist[i] = envlistQ[i];
699 i++;
700 }
701 envlist[i] = 0;
702
703 // look for the executable in the search path
704 if ( _arguments.count()>0 && getenv("PATH")!=0 ) {
705 QString command = _arguments[0];
706 if ( !command.contains( '/' ) ) {
707 QStringList pathList = QStringList::split( ':', getenv( "PATH" ) );
708 for (QStringList::Iterator it = pathList.begin(); it != pathList.end(); ++it ) {
709 QString dir = *it;
710#ifdef Q_OS_MACX
711 if(QFile::exists(dir + "/" + command + ".app")) //look in a bundle
712 dir += "/" + command + ".app/Contents/MacOS";
713#endif
714#ifndef QT_NO_DIR
715 QFileInfo fileInfo( dir, command );
716#else
717 QFileInfo fileInfo( dir + "/" + command );
718#endif
719 if ( fileInfo.isExecutable() ) {
720 arglistQ[0] = fileInfo.filePath().local8Bit();
721 arglist[0] = arglistQ[0];
722 break;
723 }
724 }
725 }
726 }
727 ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice
728 }
729 if ( fd[1] ) {
730 char buf = 0;
731 ::write( fd[1], &buf, 1 );
732 ::close( fd[1] );
733 }
734 ::exit( -1 );
735 } else if ( pid == -1 ) {
736 // error forking
737 goto error;
738 }
739
740 // test if exec was successful
741 if ( fd[1] )
742 ::close( fd[1] );
743 if ( fd[0] ) {
744 char buf;
745 for ( ;; ) {
746 int n = ::read( fd[0], &buf, 1 );
747 if ( n==1 ) {
748 // socket was not closed => error
749 d->proc = 0;
750 goto error;
751 } else if ( n==-1 ) {
752 if ( errno==EAGAIN || errno==EINTR )
753 // try it again
754 continue;
755 }
756 break;
757 }
758 ::close( fd[0] );
759 }
760
761 d->newProc( pid, this );
762
763 if ( comms & Stdin ) {
764 ::close( sStdin[0] );
765 d->proc->socketStdin = sStdin[1];
766 d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write );
767 connect( d->notifierStdin, SIGNAL(activated(int)),
768 this, SLOT(socketWrite(int)) );
769 // setup notifiers for the sockets
770 if ( !d->stdinBuf.isEmpty() ) {
771 d->notifierStdin->setEnabled( TRUE );
772 }
773 }
774 if ( comms & Stdout ) {
775 ::close( sStdout[1] );
776 d->proc->socketStdout = sStdout[0];
777 d->notifierStdout = new QSocketNotifier( sStdout[0], QSocketNotifier::Read );
778 connect( d->notifierStdout, SIGNAL(activated(int)),
779 this, SLOT(socketRead(int)) );
780 if ( ioRedirection )
781 d->notifierStdout->setEnabled( TRUE );
782 }
783 if ( comms & Stderr ) {
784 ::close( sStderr[1] );
785 d->proc->socketStderr = sStderr[0];
786 d->notifierStderr = new QSocketNotifier( sStderr[0], QSocketNotifier::Read );
787 connect( d->notifierStderr, SIGNAL(activated(int)),
788 this, SLOT(socketRead(int)) );
789 if ( ioRedirection )
790 d->notifierStderr->setEnabled( TRUE );
791 }
792
793 // cleanup and return
794 delete[] arglistQ;
795 delete[] arglist;
796 return TRUE;
797
798error:
799#if defined(QT_QPROCESS_DEBUG)
800 qDebug( "QProcess::start(): error starting process" );
801#endif
802 if ( d->procManager )
803 d->procManager->cleanup();
804 if ( comms & Stdin ) {
805 ::close( sStdin[1] );
806 ::close( sStdin[0] );
807 }
808 if ( comms & Stdout ) {
809 ::close( sStdout[0] );
810 ::close( sStdout[1] );
811 }
812 if ( comms & Stderr ) {
813 ::close( sStderr[0] );
814 ::close( sStderr[1] );
815 }
816 ::close( fd[0] );
817 ::close( fd[1] );
818 delete[] arglistQ;
819 delete[] arglist;
820 return FALSE;
821}
822
823
824/*!
825 Asks the process to terminate. Processes can ignore this wish. If you want to
826 be sure that the process really terminates, you must use kill() instead.
827
828 The slot returns immediately: it does not wait until the process has
829 finished. When the process really exited, the signal processExited() is
830 emitted.
831
832 \sa kill() processExited()
833*/
834void QProcess::tryTerminate() const
835{
836 if ( d->proc != 0 )
837 ::kill( d->proc->pid, SIGTERM );
838}
839
840/*!
841 Terminates the process. This is not a safe way to end a process since the
842 process will not be able to do cleanup. tryTerminate() is a safer way to do
843 it, but processes might ignore a tryTerminate().
844
845 The nice way to end a process and to be sure that it is finished, is doing
846 something like this:
847 \code
848 process->tryTerminate();
849 QTimer::singleShot( 5000, process, SLOT( kill() ) );
850 \endcode
851
852 This tries to terminate the process the nice way. If the process is still
853 running after 5 seconds, it terminates the process the hard way. The timeout
854 should be chosen depending on the time the process needs to do all the
855 cleanup: use a higher value if the process is likely to do heavy computation
856 on cleanup.
857
858 The slot returns immediately: it does not wait until the process has
859 finished. When the process really exited, the signal processExited() is
860 emitted.
861
862 \sa tryTerminate() processExited()
863*/
864void QProcess::kill() const
865{
866 if ( d->proc != 0 )
867 ::kill( d->proc->pid, SIGKILL );
868}
869
870/*!
871 Returns TRUE if the process is running, otherwise FALSE.
872
873 \sa normalExit() exitStatus() processExited()
874*/
875bool QProcess::isRunning() const
876{
877 if ( d->exitValuesCalculated ) {
878#if defined(QT_QPROCESS_DEBUG)
879 qDebug( "QProcess::isRunning(): FALSE (already computed)" );
880#endif
881 return FALSE;
882 }
883 if ( d->proc == 0 )
884 return FALSE;
885 int status;
886 if ( ::waitpid( d->proc->pid, &status, WNOHANG ) == d->proc->pid )
887 {
888 // compute the exit values
889 QProcess *that = (QProcess*)this; // mutable
890 that->exitNormal = WIFEXITED( status ) != 0;
891 if ( exitNormal ) {
892 that->exitStat = (char)WEXITSTATUS( status );
893 }
894 d->exitValuesCalculated = TRUE;
895#if defined(QT_QPROCESS_DEBUG)
896 qDebug( "QProcess::isRunning() (PID: %d): FALSE", d->proc->pid );
897#endif
898 return FALSE;
899 }
900#if defined(QT_QPROCESS_DEBUG)
901 qDebug( "QProcess::isRunning() (PID: %d): TRUE", d->proc->pid );
902#endif
903 return TRUE;
904}
905
906/*!
907 Writes the data \a buf to the standard input of the process. The process may
908 or may not read this data.
909
910 This function returns immediately; the QProcess class might write the data at
911 a later point (you have to enter the event loop for that). When all the data
912 is written to the process, the signal wroteToStdin() is emitted. This does
913 not mean that the process really read the data, since this class only detects
914 when it was able to write the data to the operating system.
915
916 \sa wroteToStdin() closeStdin() readStdout() readStderr()
917*/
918void QProcess::writeToStdin( const QByteArray& buf )
919{
920#if defined(QT_QPROCESS_DEBUG)
921// qDebug( "QProcess::writeToStdin(): write to stdin (%d)", d->socketStdin );
922#endif
923 d->stdinBuf.enqueue( new QByteArray(buf) );
924 if ( d->notifierStdin != 0 )
925 d->notifierStdin->setEnabled( TRUE );
926}
927
928
929/*!
930 Closes standard input of the process.
931
932 This function also deletes pending data that is not written to standard input
933 yet.
934
935 \sa wroteToStdin()
936*/
937void QProcess::closeStdin()
938{
939 if ( d->proc == 0 )
940 return;
941 if ( d->proc->socketStdin !=0 ) {
942 while ( !d->stdinBuf.isEmpty() ) {
943 delete d->stdinBuf.dequeue();
944 }
945 delete d->notifierStdin;
946 d->notifierStdin = 0;
947 if ( ::close( d->proc->socketStdin ) != 0 ) {
948 qWarning( "Could not close stdin of child process" );
949 }
950#if defined(QT_QPROCESS_DEBUG)
951 qDebug( "QProcess::closeStdin(): stdin (%d) closed", d->proc->socketStdin );
952#endif
953 d->proc->socketStdin = 0;
954 }
955}
956
957
958/*
959 This private slot is called when the process has outputted data to either
960 standard output or standard error.
961*/
962void QProcess::socketRead( int fd )
963{
964 if ( d->socketReadCalled ) {
965 // the slots that are connected to the readyRead...() signals might
966 // trigger a recursive call of socketRead(). Avoid this since you get a
967 // blocking read otherwise.
968 return;
969 }
970#if defined(QT_QPROCESS_DEBUG)
971 qDebug( "QProcess::socketRead(): %d", fd );
972#endif
973 if ( fd == 0 )
974 return;
975 const int bufsize = 4096;
976 QByteArray *buffer = 0;
977 uint oldSize;
978 int n;
979 if ( fd == d->proc->socketStdout ) {
980 buffer = &d->bufStdout;
981 } else if ( fd == d->proc->socketStderr ) {
982 buffer = &d->bufStderr;
983 } else {
984 // this case should never happen, but just to be safe
985 return;
986 }
987
988 // read data
989 oldSize = buffer->size();
990 buffer->resize( oldSize + bufsize );
991 n = ::read( fd, buffer->data()+oldSize, bufsize );
992 if ( n > 0 )
993 buffer->resize( oldSize + n );
994 else
995 buffer->resize( oldSize );
996 // eof or error?
997 if ( n == 0 || n == -1 ) {
998 if ( fd == d->proc->socketStdout ) {
999#if defined(QT_QPROCESS_DEBUG)
1000 qDebug( "QProcess::socketRead(): stdout (%d) closed", fd );
1001#endif
1002 d->notifierStdout->setEnabled( FALSE );
1003 delete d->notifierStdout;
1004 d->notifierStdout = 0;
1005 ::close( d->proc->socketStdout );
1006 d->proc->socketStdout = 0;
1007 return;
1008 } else if ( fd == d->proc->socketStderr ) {
1009#if defined(QT_QPROCESS_DEBUG)
1010 qDebug( "QProcess::socketRead(): stderr (%d) closed", fd );
1011#endif
1012 d->notifierStderr->setEnabled( FALSE );
1013 delete d->notifierStderr;
1014 d->notifierStderr = 0;
1015 ::close( d->proc->socketStderr );
1016 d->proc->socketStderr = 0;
1017 return;
1018 }
1019 }
1020 // read all data that is available
1021 while ( n == bufsize ) {
1022 oldSize = buffer->size();
1023 buffer->resize( oldSize + bufsize );
1024 n = ::read( fd, buffer->data()+oldSize, bufsize );
1025 if ( n > 0 )
1026 buffer->resize( oldSize + n );
1027 else
1028 buffer->resize( oldSize );
1029 }
1030
1031 d->socketReadCalled = TRUE;
1032 if ( fd == d->proc->socketStdout ) {
1033#if defined(QT_QPROCESS_DEBUG)
1034 qDebug( "QProcess::socketRead(): %d bytes read from stdout (%d)",
1035 buffer->size()-oldSize, fd );
1036#endif
1037 emit readyReadStdout();
1038 } else if ( fd == d->proc->socketStderr ) {
1039#if defined(QT_QPROCESS_DEBUG)
1040 qDebug( "QProcess::socketRead(): %d bytes read from stderr (%d)",
1041 buffer->size()-oldSize, fd );
1042#endif
1043 emit readyReadStderr();
1044 }
1045 d->socketReadCalled = FALSE;
1046}
1047
1048
1049/*
1050 This private slot is called when the process tries to read data from standard
1051 input.
1052*/
1053void QProcess::socketWrite( int fd )
1054{
1055 if ( fd != d->proc->socketStdin || d->proc->socketStdin == 0 )
1056 return;
1057 if ( d->stdinBuf.isEmpty() ) {
1058 d->notifierStdin->setEnabled( FALSE );
1059 return;
1060 }
1061#if defined(QT_QPROCESS_DEBUG)
1062 qDebug( "QProcess::socketWrite(): write to stdin (%d)", fd );
1063#endif
1064 ssize_t ret = ::write( fd,
1065 d->stdinBuf.head()->data() + d->stdinBufRead,
1066 d->stdinBuf.head()->size() - d->stdinBufRead );
1067 if ( ret > 0 )
1068 d->stdinBufRead += ret;
1069 if ( d->stdinBufRead == (ssize_t)d->stdinBuf.head()->size() ) {
1070 d->stdinBufRead = 0;
1071 delete d->stdinBuf.dequeue();
1072 if ( wroteToStdinConnected && d->stdinBuf.isEmpty() )
1073 emit wroteToStdin();
1074 socketWrite( fd );
1075 }
1076}
1077
1078/*!
1079 \internal
1080 Flushes standard input. This is useful if you want to use QProcess in a
1081 synchronous manner.
1082
1083 This function should probably go into the public API.
1084*/
1085void QProcess::flushStdin()
1086{
1087 socketWrite( d->proc->socketStdin );
1088}
1089
1090/*
1091 This private slot is only used under Windows (but moc does not know about #if
1092 defined()).
1093*/
1094void QProcess::timeout()
1095{
1096}
1097
1098
1099/*
1100 This private function is used by connectNotify() and disconnectNotify() to
1101 change the value of ioRedirection (and related behaviour)
1102*/
1103void QProcess::setIoRedirection( bool value )
1104{
1105 ioRedirection = value;
1106 if ( ioRedirection ) {
1107 if ( d->notifierStdout )
1108 d->notifierStdout->setEnabled( TRUE );
1109 if ( d->notifierStderr )
1110 d->notifierStderr->setEnabled( TRUE );
1111 } else {
1112 if ( d->notifierStdout )
1113 d->notifierStdout->setEnabled( FALSE );
1114 if ( d->notifierStderr )
1115 d->notifierStderr->setEnabled( FALSE );
1116 }
1117}
1118
1119/*
1120 This private function is used by connectNotify() and
1121 disconnectNotify() to change the value of notifyOnExit (and related
1122 behaviour)
1123*/
1124void QProcess::setNotifyOnExit( bool value )
1125{
1126 notifyOnExit = value;
1127}
1128
1129/*
1130 This private function is used by connectNotify() and disconnectNotify() to
1131 change the value of wroteToStdinConnected (and related behaviour)
1132*/
1133void QProcess::setWroteStdinConnected( bool value )
1134{
1135 wroteToStdinConnected = value;
1136}
1137
1138/*! \enum QProcess::PID
1139 \internal
1140*/
1141/*!
1142 Returns platform dependent information about the process. This can be used
1143 together with platform specific system calls.
1144
1145 Under Unix the return value is the PID of the process, or -1 if no process is
1146 belonging to this object.
1147
1148 Under Windows it is a pointer to the \c PROCESS_INFORMATION struct, or 0 if
1149 no process is belonging to this object.
1150*/
1151QProcess::PID QProcess::processIdentifier()
1152{
1153 if ( d->proc == 0 )
1154 return -1;
1155 return d->proc->pid;
1156}
1157
1158#endif // QT_NO_PROCESS
diff --git a/import.log b/import.log
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/import.log
diff --git a/library/fileselector_p.h b/library/fileselector_p.h
new file mode 100644
index 0000000..6bab485
--- a/dev/null
+++ b/library/fileselector_p.h
@@ -0,0 +1,56 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20#ifndef FILESELECTOR_P_H
21#define FILESELECTOR_P_H
22
23#include <qlistview.h>
24
25class FileManager;
26class CategoryMenu;
27class FileSelectorViewPrivate;
28
29class FileSelectorView : public QListView
30{
31 Q_OBJECT
32
33public:
34 FileSelectorView( const QString &mimefilter, QWidget *parent, const char *name );
35 ~FileSelectorView();
36 void reread();
37 int fileCount() { return count; }
38
39 void setCategoryFilter(CategoryMenu *);
40protected:
41 void keyPressEvent( QKeyEvent *e );
42
43protected slots:
44 void cardMessage( const QCString &, const QByteArray &);
45
46 void categoryChanged();
47
48private:
49 QString filter;
50 FileManager *fileManager;
51 int count;
52 FileSelectorViewPrivate *d;
53};
54
55
56#endif
diff --git a/library/mediaplayerplugininterface.h b/library/mediaplayerplugininterface.h
new file mode 100644
index 0000000..4aa28ec
--- a/dev/null
+++ b/library/mediaplayerplugininterface.h
@@ -0,0 +1,110 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20#ifndef MEDIA_PLAYER_PLUGIN_INTERFACE_H
21#define MEDIA_PLAYER_PLUGIN_INTERFACE_H
22
23#include <qpe/qcom.h>
24
25#ifndef QT_NO_COMPONENT
26// {c0093632-b44c-4cf7-a279-d82fe8a8890c}
27# ifndef IID_MediaPlayerPlugin
28# define IID_MediaPlayerPlugin QUuid( 0xc0093632, 0xb44c, 0x4cf7, 0xa2, 0x79, 0xd8, 0x2f, 0xe8, 0xa8, 0x89, 0x0c )
29# endif
30#endif
31
32
33enum ColorFormat {
34 RGB565,
35 BGR565,
36 RGBA8888,
37 BGRA8888
38};
39
40
41class MediaPlayerDecoder {
42
43public:
44 virtual ~MediaPlayerDecoder() { };
45
46 // About Plugin
47 virtual const char *pluginName() = 0;
48 virtual const char *pluginComment() = 0;
49 virtual double pluginVersion() = 0;
50
51 virtual bool isFileSupported( const QString& file ) = 0;
52 virtual bool open( const QString& file ) = 0;
53 virtual bool close() = 0;
54 virtual bool isOpen() = 0;
55 virtual const QString &fileInfo() = 0;
56
57 // If decoder doesn't support audio then return 0 here
58 virtual int audioStreams() = 0;
59 virtual int audioChannels( int stream ) = 0;
60 virtual int audioFrequency( int stream ) = 0;
61 virtual int audioSamples( int stream ) = 0;
62 virtual bool audioSetSample( long sample, int stream ) = 0;
63 virtual long audioGetSample( int stream ) = 0;
64 virtual bool audioReadSamples( short *samples, int channels, long samples, long& samplesRead, int stream ) = 0;
65
66 // If decoder doesn't support video then return 0 here
67 virtual int videoStreams() = 0;
68 virtual int videoWidth( int stream ) = 0;
69 virtual int videoHeight( int stream ) = 0;
70 virtual double videoFrameRate( int stream ) = 0; // frames per second (this may change to frames/1000secs)
71 virtual int videoFrames( int stream ) = 0;
72 virtual bool videoSetFrame( long sample, int stream ) = 0;
73 virtual long videoGetFrame( int stream ) = 0;
74 virtual bool videoReadFrame( unsigned char **output_rows, int in_x, int in_y, int in_w, int in_h, ColorFormat color_model, int stream ) = 0;
75 virtual bool videoReadScaledFrame( unsigned char **output_rows, int in_x, int in_y, int in_w, int in_h, int out_w, int out_h, ColorFormat color_model, int stream ) = 0;
76 virtual bool videoReadYUVFrame( char *y_output, char *u_output, char *v_output, int in_x, int in_y, int in_w, int in_h, int stream ) = 0;
77
78 // Profiling
79 virtual double getTime() = 0;
80
81 // Ignore if these aren't supported
82 virtual bool setSMP( int cpus ) = 0;
83 virtual bool setMMX( bool useMMX ) = 0;
84
85 // Capabilities
86 virtual bool supportsAudio() = 0;
87 virtual bool supportsVideo() = 0;
88 virtual bool supportsYUV() = 0;
89 virtual bool supportsMMX() = 0;
90 virtual bool supportsSMP() = 0;
91 virtual bool supportsStereo() = 0;
92 virtual bool supportsScaling() = 0;
93
94 // File Properies
95 virtual long getPlayTime() { return -1; }
96};
97
98
99class MediaPlayerEncoder;
100
101
102struct MediaPlayerPluginInterface : public QUnknownInterface
103{
104 virtual MediaPlayerDecoder *decoder() = 0;
105 virtual MediaPlayerEncoder *encoder() = 0;
106};
107
108
109#endif
110
diff --git a/pics/cards/card_back0001_small.png b/pics/cards/card_back0001_small.png
new file mode 100644
index 0000000..11d085c
--- a/dev/null
+++ b/pics/cards/card_back0001_small.png
Binary files differ
diff --git a/pics/cards/card_back0002_small.png b/pics/cards/card_back0002_small.png
new file mode 100644
index 0000000..d7d4279
--- a/dev/null
+++ b/pics/cards/card_back0002_small.png
Binary files differ
diff --git a/pics/cards/card_back0003_small.png b/pics/cards/card_back0003_small.png
new file mode 100644
index 0000000..690d103
--- a/dev/null
+++ b/pics/cards/card_back0003_small.png
Binary files differ
diff --git a/pics/cards/card_back0004_small.png b/pics/cards/card_back0004_small.png
new file mode 100644
index 0000000..6a7c23f
--- a/dev/null
+++ b/pics/cards/card_back0004_small.png
Binary files differ
diff --git a/pics/cards/card_back0005_small.png b/pics/cards/card_back0005_small.png
new file mode 100644
index 0000000..752c987
--- a/dev/null
+++ b/pics/cards/card_back0005_small.png
Binary files differ
diff --git a/pics/cards/card_chars_small.png b/pics/cards/card_chars_small.png
new file mode 100644
index 0000000..2637870
--- a/dev/null
+++ b/pics/cards/card_chars_small.png
Binary files differ
diff --git a/pics/cards/card_face_small.png b/pics/cards/card_face_small.png
new file mode 100644
index 0000000..6ee9484
--- a/dev/null
+++ b/pics/cards/card_face_small.png
Binary files differ
diff --git a/pics/cards/card_suits_small.png b/pics/cards/card_suits_small.png
new file mode 100644
index 0000000..8fe919c
--- a/dev/null
+++ b/pics/cards/card_suits_small.png
Binary files differ