KDECore
kprocess.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kprocess_p.h"
00023
00024 #include <kstandarddirs.h>
00025 #include <kshell.h>
00026 #ifdef Q_OS_WIN
00027 # include <kshell_p.h>
00028 #endif
00029
00030 #include <qfile.h>
00031
00032 #ifdef Q_OS_WIN
00033 # include <windows.h>
00034 #else
00035 # include <unistd.h>
00036 # include <errno.h>
00037 #endif
00038
00039 #ifndef Q_OS_WIN
00040 # define STD_OUTPUT_HANDLE 1
00041 # define STD_ERROR_HANDLE 2
00042 #endif
00043
00044 void KProcessPrivate::writeAll(const QByteArray &buf, int fd)
00045 {
00046 #ifdef Q_OS_WIN
00047 HANDLE h = GetStdHandle(fd);
00048 if (h) {
00049 DWORD wr;
00050 WriteFile(h, buf.data(), buf.size(), &wr, 0);
00051 }
00052 #else
00053 int off = 0;
00054 do {
00055 int ret = ::write(fd, buf.data() + off, buf.size() - off);
00056 if (ret < 0) {
00057 if (errno != EINTR)
00058 return;
00059 } else {
00060 off += ret;
00061 }
00062 } while (off < buf.size());
00063 #endif
00064 }
00065
00066 void KProcessPrivate::forwardStd(KProcess::ProcessChannel good, int fd)
00067 {
00068 Q_Q(KProcess);
00069
00070 QProcess::ProcessChannel oc = q->readChannel();
00071 q->setReadChannel(good);
00072 writeAll(q->readAll(), fd);
00073 q->setReadChannel(oc);
00074 }
00075
00076 void KProcessPrivate::_k_forwardStdout()
00077 {
00078 forwardStd(KProcess::StandardOutput, STD_OUTPUT_HANDLE);
00079 }
00080
00081 void KProcessPrivate::_k_forwardStderr()
00082 {
00083 forwardStd(KProcess::StandardError, STD_ERROR_HANDLE);
00084 }
00085
00087
00089
00090 KProcess::KProcess(QObject *parent) :
00091 QProcess(parent),
00092 d_ptr(new KProcessPrivate)
00093 {
00094 d_ptr->q_ptr = this;
00095 setOutputChannelMode(ForwardedChannels);
00096 }
00097
00098 KProcess::KProcess(KProcessPrivate *d, QObject *parent) :
00099 QProcess(parent),
00100 d_ptr(d)
00101 {
00102 d_ptr->q_ptr = this;
00103 setOutputChannelMode(ForwardedChannels);
00104 }
00105
00106 KProcess::~KProcess()
00107 {
00108 delete d_ptr;
00109 }
00110
00111 void KProcess::setOutputChannelMode(OutputChannelMode mode)
00112 {
00113 Q_D(KProcess);
00114
00115 d->outputChannelMode = mode;
00116 disconnect(this, SIGNAL(readyReadStandardOutput()));
00117 disconnect(this, SIGNAL(readyReadStandardError()));
00118 switch (mode) {
00119 case OnlyStdoutChannel:
00120 connect(this, SIGNAL(readyReadStandardError()), SLOT(_k_forwardStderr()));
00121 break;
00122 case OnlyStderrChannel:
00123 connect(this, SIGNAL(readyReadStandardOutput()), SLOT(_k_forwardStdout()));
00124 break;
00125 default:
00126 QProcess::setProcessChannelMode((ProcessChannelMode)mode);
00127 return;
00128 }
00129 QProcess::setProcessChannelMode(QProcess::SeparateChannels);
00130 }
00131
00132 KProcess::OutputChannelMode KProcess::outputChannelMode() const
00133 {
00134 Q_D(const KProcess);
00135
00136 return d->outputChannelMode;
00137 }
00138
00139 void KProcess::setNextOpenMode(QIODevice::OpenMode mode)
00140 {
00141 Q_D(KProcess);
00142
00143 d->openMode = mode;
00144 }
00145
00146 #define DUMMYENV "_KPROCESS_DUMMY_="
00147
00148 void KProcess::clearEnvironment()
00149 {
00150 setEnvironment(QStringList() << QString::fromLatin1(DUMMYENV));
00151 }
00152
00153 void KProcess::setEnv(const QString &name, const QString &value, bool overwrite)
00154 {
00155 QStringList env = environment();
00156 if (env.isEmpty()) {
00157 env = systemEnvironment();
00158 env.removeAll(QString::fromLatin1(DUMMYENV));
00159 }
00160 QString fname(name);
00161 fname.append('=');
00162 for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
00163 if ((*it).startsWith(fname)) {
00164 if (overwrite) {
00165 *it = fname.append(value);
00166 setEnvironment(env);
00167 }
00168 return;
00169 }
00170 env.append(fname.append(value));
00171 setEnvironment(env);
00172 }
00173
00174 void KProcess::unsetEnv(const QString &name)
00175 {
00176 QStringList env = environment();
00177 if (env.isEmpty()) {
00178 env = systemEnvironment();
00179 env.removeAll(QString::fromLatin1(DUMMYENV));
00180 }
00181 QString fname(name);
00182 fname.append('=');
00183 for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
00184 if ((*it).startsWith(fname)) {
00185 env.erase(it);
00186 if (env.isEmpty())
00187 env.append(DUMMYENV);
00188 setEnvironment(env);
00189 return;
00190 }
00191 }
00192
00193 void KProcess::setProgram(const QString &exe, const QStringList &args)
00194 {
00195 Q_D(KProcess);
00196
00197 d->prog = exe;
00198 d->args = args;
00199 }
00200
00201 void KProcess::setProgram(const QStringList &argv)
00202 {
00203 Q_D(KProcess);
00204
00205 Q_ASSERT( !argv.isEmpty() );
00206 d->args = argv;
00207 d->prog = d->args.takeFirst();
00208 }
00209
00210 KProcess &KProcess::operator<<(const QString &arg)
00211 {
00212 Q_D(KProcess);
00213
00214 if (d->prog.isEmpty())
00215 d->prog = arg;
00216 else
00217 d->args << arg;
00218 return *this;
00219 }
00220
00221 KProcess &KProcess::operator<<(const QStringList &args)
00222 {
00223 Q_D(KProcess);
00224
00225 if (d->prog.isEmpty())
00226 setProgram(args);
00227 else
00228 d->args << args;
00229 return *this;
00230 }
00231
00232 void KProcess::clearProgram()
00233 {
00234 Q_D(KProcess);
00235
00236 d->prog.clear();
00237 d->args.clear();
00238 }
00239
00240 void KProcess::setShellCommand(const QString &cmd)
00241 {
00242 Q_D(KProcess);
00243
00244 KShell::Errors err;
00245 d->args = KShell::splitArgs(
00246 cmd, KShell::AbortOnMeta | KShell::TildeExpand, &err);
00247 if (err == KShell::NoError && !d->args.isEmpty()) {
00248 d->prog = KStandardDirs::findExe(d->args[0]);
00249 if (!d->prog.isEmpty()) {
00250 d->args.removeFirst();
00251 return;
00252 }
00253 }
00254
00255 d->args.clear();
00256
00257 #ifdef Q_OS_UNIX
00258
00259 # if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__GNU__)
00260
00261
00262
00263 d->prog = QFile::symLinkTarget(QString::fromLatin1("/bin/sh"));
00264 if (d->prog.isEmpty()) {
00265
00266 d->prog = KStandardDirs::findExe("ksh");
00267 if (d->prog.isEmpty()) {
00268 d->prog = KStandardDirs::findExe("ash");
00269 if (d->prog.isEmpty()) {
00270 d->prog = KStandardDirs::findExe("bash");
00271 if (d->prog.isEmpty()) {
00272 d->prog = KStandardDirs::findExe("zsh");
00273 if (d->prog.isEmpty())
00274
00275 d->prog = QString::fromLatin1("/bin/sh");
00276 }
00277 }
00278 }
00279 }
00280 # else
00281 d->prog = QString::fromLatin1("/bin/sh");
00282 # endif
00283
00284 d->args << "-c" << cmd;
00285 #else // Q_OS_UNIX
00286
00287
00288 setEnv(PERCENT_VARIABLE, "%");
00289
00290
00291 d->prog = KStandardDirs::findExe("kcmdwrapper");
00292
00293 UINT size;
00294 WCHAR sysdir[MAX_PATH + 1];
00295 size = GetSystemDirectoryW(sysdir, MAX_PATH + 1);
00296 QString cmdexe = QString::fromUtf16((const ushort *) sysdir, size);
00297 cmdexe.append("\\cmd.exe");
00298
00299 d->args << cmdexe << cmd;
00300 #endif
00301 }
00302
00303 QStringList KProcess::program() const
00304 {
00305 Q_D(const KProcess);
00306
00307 QStringList argv = d->args;
00308 argv.prepend(d->prog);
00309 return argv;
00310 }
00311
00312 void KProcess::start()
00313 {
00314 Q_D(KProcess);
00315
00316 QProcess::start(d->prog, d->args, d->openMode);
00317 }
00318
00319 int KProcess::execute(int msecs)
00320 {
00321 start();
00322 if (!waitForFinished(msecs)) {
00323 kill();
00324 waitForFinished(-1);
00325 return -2;
00326 }
00327 return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1;
00328 }
00329
00330
00331 int KProcess::execute(const QString &exe, const QStringList &args, int msecs)
00332 {
00333 KProcess p;
00334 p.setProgram(exe, args);
00335 return p.execute(msecs);
00336 }
00337
00338
00339 int KProcess::execute(const QStringList &argv, int msecs)
00340 {
00341 KProcess p;
00342 p.setProgram(argv);
00343 return p.execute(msecs);
00344 }
00345
00346 int KProcess::startDetached()
00347 {
00348 Q_D(KProcess);
00349
00350 qint64 pid;
00351 if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid))
00352 return 0;
00353 return (int) pid;
00354 }
00355
00356
00357 int KProcess::startDetached(const QString &exe, const QStringList &args)
00358 {
00359 qint64 pid;
00360 if (!QProcess::startDetached(exe, args, QString(), &pid))
00361 return 0;
00362 return (int) pid;
00363 }
00364
00365
00366 int KProcess::startDetached(const QStringList &argv)
00367 {
00368 QStringList args = argv;
00369 QString prog = args.takeFirst();
00370 return startDetached(prog, args);
00371 }
00372
00373 int KProcess::pid() const
00374 {
00375 #ifdef Q_OS_UNIX
00376 return (int) QProcess::pid();
00377 #else
00378 return QProcess::pid() ? QProcess::pid()->dwProcessId : 0;
00379 #endif
00380 }
00381
00382 #include "kprocess.moc"