1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QPROCESS_H
41 #define QPROCESS_H
42 
43 #include <QtCore/qiodevice.h>
44 #include <QtCore/qstringlist.h>
45 #include <QtCore/qshareddata.h>
46 
47 #include <functional>
48 
49 QT_REQUIRE_CONFIG(processenvironment);
50 
51 #ifdef Q_OS_WIN
52 typedef struct _PROCESS_INFORMATION *Q_PID;
53 #endif
54 
55 #if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
56 typedef struct _SECURITY_ATTRIBUTES Q_SECURITY_ATTRIBUTES;
57 typedef struct _STARTUPINFOW Q_STARTUPINFO;
58 #endif
59 
60 QT_BEGIN_NAMESPACE
61 
62 class QProcessPrivate;
63 class QProcessEnvironmentPrivate;
64 
65 #ifndef Q_OS_WIN
66 typedef qint64 Q_PID;
67 #endif
68 
69 class Q_CORE_EXPORT QProcessEnvironment
70 {
71 public:
72     QProcessEnvironment();
73     QProcessEnvironment(const QProcessEnvironment &other);
74     ~QProcessEnvironment();
75     QProcessEnvironment &operator=(QProcessEnvironment && other) noexcept { swap(other); return *this; }
76     QProcessEnvironment &operator=(const QProcessEnvironment &other);
77 
swap(QProcessEnvironment & other)78     void swap(QProcessEnvironment &other) noexcept { qSwap(d, other.d); }
79 
80     bool operator==(const QProcessEnvironment &other) const;
81     inline bool operator!=(const QProcessEnvironment &other) const
82     { return !(*this == other); }
83 
84     bool isEmpty() const;
85     void clear();
86 
87     bool contains(const QString &name) const;
88     void insert(const QString &name, const QString &value);
89     void remove(const QString &name);
90     QString value(const QString &name, const QString &defaultValue = QString()) const;
91 
92     QStringList toStringList() const;
93 
94     QStringList keys() const;
95 
96     void insert(const QProcessEnvironment &e);
97 
98     static QProcessEnvironment systemEnvironment();
99 
100 private:
101     friend class QProcessPrivate;
102     friend class QProcessEnvironmentPrivate;
103     QSharedDataPointer<QProcessEnvironmentPrivate> d;
104 };
105 
Q_DECLARE_SHARED(QProcessEnvironment)106 Q_DECLARE_SHARED(QProcessEnvironment)
107 
108 #if QT_CONFIG(process)
109 
110 class Q_CORE_EXPORT QProcess : public QIODevice
111 {
112     Q_OBJECT
113 public:
114     enum ProcessError {
115         FailedToStart, //### file not found, resource error
116         Crashed,
117         Timedout,
118         ReadError,
119         WriteError,
120         UnknownError
121     };
122     Q_ENUM(ProcessError)
123 
124     enum ProcessState {
125         NotRunning,
126         Starting,
127         Running
128     };
129     Q_ENUM(ProcessState)
130 
131     enum ProcessChannel {
132         StandardOutput,
133         StandardError
134     };
135     Q_ENUM(ProcessChannel)
136 
137     enum ProcessChannelMode {
138         SeparateChannels,
139         MergedChannels,
140         ForwardedChannels,
141         ForwardedOutputChannel,
142         ForwardedErrorChannel
143     };
144     Q_ENUM(ProcessChannelMode)
145 
146     enum InputChannelMode {
147         ManagedInputChannel,
148         ForwardedInputChannel
149     };
150     Q_ENUM(InputChannelMode)
151 
152     enum ExitStatus {
153         NormalExit,
154         CrashExit
155     };
156     Q_ENUM(ExitStatus)
157 
158     explicit QProcess(QObject *parent = nullptr);
159     virtual ~QProcess();
160 
161     void start(const QString &program, const QStringList &arguments, OpenMode mode = ReadWrite);
162 #if !defined(QT_NO_PROCESS_COMBINED_ARGUMENT_START)
163 #if QT_DEPRECATED_SINCE(5, 15)
164     QT_DEPRECATED_X(
165         "Use QProcess::start(const QString &program, const QStringList &arguments,"
166         "OpenMode mode = ReadWrite) instead"
167     )
168     void start(const QString &command, OpenMode mode = ReadWrite);
169 #endif
170 #endif
171     void start(OpenMode mode = ReadWrite);
172     bool startDetached(qint64 *pid = nullptr);
173     bool open(OpenMode mode = ReadWrite) override;
174 
175     QString program() const;
176     void setProgram(const QString &program);
177 
178     QStringList arguments() const;
179     void setArguments(const QStringList & arguments);
180 
181 #if QT_DEPRECATED_SINCE(5, 13)
182     QT_DEPRECATED_X("Use QProcess::processChannelMode() instead")
183     ProcessChannelMode readChannelMode() const;
184     QT_DEPRECATED_X("Use QProcess::setProcessChannelMode() instead")
185     void setReadChannelMode(ProcessChannelMode mode);
186 #endif
187     ProcessChannelMode processChannelMode() const;
188     void setProcessChannelMode(ProcessChannelMode mode);
189     InputChannelMode inputChannelMode() const;
190     void setInputChannelMode(InputChannelMode mode);
191 
192     ProcessChannel readChannel() const;
193     void setReadChannel(ProcessChannel channel);
194 
195     void closeReadChannel(ProcessChannel channel);
196     void closeWriteChannel();
197 
198     void setStandardInputFile(const QString &fileName);
199     void setStandardOutputFile(const QString &fileName, OpenMode mode = Truncate);
200     void setStandardErrorFile(const QString &fileName, OpenMode mode = Truncate);
201     void setStandardOutputProcess(QProcess *destination);
202 
203 #if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
204     QString nativeArguments() const;
205     void setNativeArguments(const QString &arguments);
206     struct CreateProcessArguments
207     {
208         const wchar_t *applicationName;
209         wchar_t *arguments;
210         Q_SECURITY_ATTRIBUTES *processAttributes;
211         Q_SECURITY_ATTRIBUTES *threadAttributes;
212         bool inheritHandles;
213         unsigned long flags;
214         void *environment;
215         const wchar_t *currentDirectory;
216         Q_STARTUPINFO *startupInfo;
217         Q_PID processInformation;
218     };
219     typedef std::function<void(CreateProcessArguments *)> CreateProcessArgumentModifier;
220     CreateProcessArgumentModifier createProcessArgumentsModifier() const;
221     void setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier);
222 #endif // Q_OS_WIN || Q_CLANG_QDOC
223 
224     QString workingDirectory() const;
225     void setWorkingDirectory(const QString &dir);
226 
227     void setEnvironment(const QStringList &environment);
228     QStringList environment() const;
229     void setProcessEnvironment(const QProcessEnvironment &environment);
230     QProcessEnvironment processEnvironment() const;
231 
232     QProcess::ProcessError error() const;
233     QProcess::ProcessState state() const;
234 
235 #if QT_DEPRECATED_SINCE(5, 15)
236     QT_DEPRECATED_VERSION_X_5_15("Use processId() instead")
237     Q_PID pid() const;
238 #endif
239     qint64 processId() const;
240 
241     bool waitForStarted(int msecs = 30000);
242     bool waitForReadyRead(int msecs = 30000) override;
243     bool waitForBytesWritten(int msecs = 30000) override;
244     bool waitForFinished(int msecs = 30000);
245 
246     QByteArray readAllStandardOutput();
247     QByteArray readAllStandardError();
248 
249     int exitCode() const;
250     QProcess::ExitStatus exitStatus() const;
251 
252     // QIODevice
253     qint64 bytesAvailable() const override; // ### Qt6: remove trivial override
254     qint64 bytesToWrite() const override;
255     bool isSequential() const override;
256     bool canReadLine() const override; // ### Qt6: remove trivial override
257     void close() override;
258     bool atEnd() const override; // ### Qt6: remove trivial override
259 
260     static int execute(const QString &program, const QStringList &arguments);
261 #if QT_DEPRECATED_SINCE(5, 15)
262     QT_DEPRECATED_X(
263         "Use QProcess::execute(const QString &program, const QStringList &arguments) instead"
264     )
265     static int execute(const QString &command);
266 #endif
267     static bool startDetached(const QString &program, const QStringList &arguments,
268                               const QString &workingDirectory
269 #if defined(Q_QDOC)
270                               = QString()
271 #endif
272                               , qint64 *pid = nullptr);
273 #if !defined(Q_QDOC)
274     static bool startDetached(const QString &program, const QStringList &arguments); // ### Qt6: merge overloads
275 #endif
276 #if QT_DEPRECATED_SINCE(5, 15)
277     QT_DEPRECATED_X(
278         "Use QProcess::startDetached(const QString &program, const QStringList &arguments) instead"
279     )
280     static bool startDetached(const QString &command);
281 #endif
282 
283     static QStringList systemEnvironment();
284 
285     static QString nullDevice();
286 
287     static QStringList splitCommand(QStringView command);
288 
289 public Q_SLOTS:
290     void terminate();
291     void kill();
292 
293 Q_SIGNALS:
294     void started(QPrivateSignal);
295 #if QT_DEPRECATED_SINCE(5, 13)
296     QT_DEPRECATED_X("Use QProcess::finished(int, QProcess::ExitStatus) instead")
297     void finished(int exitCode); // ### Qt 6: merge the two signals with a default value
298 #endif
299     void finished(int exitCode, QProcess::ExitStatus exitStatus);
300 #if QT_DEPRECATED_SINCE(5, 6)
301     QT_DEPRECATED_X("Use QProcess::errorOccurred(QProcess::ProcessError) instead")
302     void error(QProcess::ProcessError error);
303 #endif
304     void errorOccurred(QProcess::ProcessError error);
305     void stateChanged(QProcess::ProcessState state, QPrivateSignal);
306 
307     void readyReadStandardOutput(QPrivateSignal);
308     void readyReadStandardError(QPrivateSignal);
309 
310 protected:
311     void setProcessState(ProcessState state);
312 
313     virtual void setupChildProcess();
314 
315     // QIODevice
316     qint64 readData(char *data, qint64 maxlen) override;
317     qint64 writeData(const char *data, qint64 len) override;
318 
319 private:
320     Q_DECLARE_PRIVATE(QProcess)
321     Q_DISABLE_COPY(QProcess)
322 
323     Q_PRIVATE_SLOT(d_func(), bool _q_canReadStandardOutput())
324     Q_PRIVATE_SLOT(d_func(), bool _q_canReadStandardError())
325     Q_PRIVATE_SLOT(d_func(), bool _q_canWrite())
326     Q_PRIVATE_SLOT(d_func(), bool _q_startupNotification())
327     Q_PRIVATE_SLOT(d_func(), bool _q_processDied())
328     friend class QProcessManager;
329 };
330 
331 #endif // QT_CONFIG(process)
332 
333 QT_END_NAMESPACE
334 
335 #endif // QPROCESS_H
336