• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • util
kshell_win.cpp
Go to the documentation of this file.
1/*
2 This file is part of the KDE libraries
3
4 Copyright (c) 2007 Bernhard Loos <nhuh.put@web.de>
5 Copyright (c) 2007,2008 Oswald Buddenhagen <ossi@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23#include "kshell.h"
24#include "kshell_p.h"
25
26#include <kkernel_win.h>
27
28#include <QString>
29#include <QStringList>
30#include <QtCore/QDir>
31
32/*
33 * A short introduction into cmd semantics:
34 * - Variable expansion is done first, without regard to *any* escaping -
35 * if something looks like an existing variable, it is replaced.
36 * - Then follows regular tokenization by the shell. &, &&, | and || are
37 * command delimiters. ( and ) are command grouping operators; they are
38 * recognized only a the start resp. end of a command; mismatched )s are
39 * an error if any (s are present. <, > are just like under UNIX - they can
40 * appear *anywhere* in a command, perform their function and are cut out.
41 * @ at the start of a command is eaten (local echo off - no function as
42 * far as cmd /c is concerned). : at the start of a command declares a label,
43 * which effectively means the remainder of the line is a comment - note that
44 * command separators are not recognized past that point.
45 * ^ is the escape char for everything including itself.
46 * cmd ignores *all* special chars between double quotes, so there is no
47 * way to escape the closing quote. Note that the quotes are *not* removed
48 * from the resulting command line.
49 * - Then follows delayed variable expansion if it is enabled and at least
50 * one exclamation mark is present. This involves another layer of ^
51 * escaping, regardless of quotes. (Win2k+)
52 * - Then follows argument splitting as described in
53 * http://msdn2.microsoft.com/en-us/library/ms880421.aspx .
54 * Note that this is done by the called application and therefore might
55 * be subject to completely different semantics, in fact.
56 */
57
58inline static bool isMetaChar(ushort c)
59{
60 static const uchar iqm[] = {
61 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x50,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
63 }; // &()<>|
64
65 return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
66}
67
68inline static bool isSpecialChar(ushort c)
69{
70 // Chars that should be quoted (TM). This includes:
71 // - control chars & space
72 // - the shell meta chars &()<>^|
73 // - the potential separators ,;=
74 static const uchar iqm[] = {
75 0xff, 0xff, 0xff, 0xff, 0x41, 0x13, 0x00, 0x78,
76 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
77 };
78
79 return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
80}
81
82inline static bool isWhiteSpace(ushort c)
83{
84 return c == ' ' || c == '\t';
85}
86
87QStringList KShell::splitArgs(const QString &_args, Options flags, Errors *err)
88{
89 QString args(_args);
90 QStringList ret;
91
92 const QLatin1Char bs('\\'), dq('\"');
93
94 if (flags & AbortOnMeta) {
95 args.remove(PERCENT_ESCAPE);
96 if (args.indexOf(QLatin1Char('%')) >= 0) {
97 if (err)
98 *err = FoundMeta;
99 return QStringList();
100 }
101
102 args = _args;
103 args.replace(PERCENT_ESCAPE, QLatin1String("%"));
104
105 if (!args.isEmpty() && args[0].unicode() == '@')
106 args.remove(0, 1);
107
108 for (int p = 0; p < args.length(); p++) {
109 ushort c = args[p].unicode();
110 if (c == '^') {
111 args.remove(p, 1);
112 } else if (c == '"') {
113 while (++p < args.length() && args[p].unicode() != '"')
114 ;
115 } else if (isMetaChar(c)) {
116 if (err)
117 *err = FoundMeta;
118 return QStringList();
119 }
120 }
121 }
122
123 if (err)
124 *err = NoError;
125
126 int p = 0;
127 const int length = args.length();
128 forever {
129 while (p < length && isWhiteSpace(args[p].unicode()))
130 ++p;
131 if (p == length)
132 return ret;
133
134 QString arg;
135 bool inquote = false;
136 forever {
137 bool copy = true; // copy this char
138 int bslashes = 0; // number of preceding backslashes to insert
139 while (p < length && args[p] == bs) {
140 ++p;
141 ++bslashes;
142 }
143 if (p < length && args[p] == dq) {
144 if (bslashes % 2 == 0) {
145 // Even number of backslashes, so the quote is not escaped.
146 if (inquote) {
147 if (p + 1 < length && args[p + 1] == dq) {
148 // Two consecutive quotes make a literal quote.
149 // This is not documented on MSDN.
150 ++p;
151 } else {
152 // Closing quote
153 copy = false;
154 inquote = !inquote;
155 }
156 } else {
157 // Opening quote
158 copy = false;
159 inquote = !inquote;
160 }
161 }
162 bslashes /= 2;
163 }
164
165 while (--bslashes >= 0)
166 arg.append(bs);
167
168 if (p == length || (!inquote && isWhiteSpace(args[p].unicode()))) {
169 ret.append(arg);
170 if (inquote) {
171 if (err)
172 *err = BadQuoting;
173 return QStringList();
174 }
175 break;
176 }
177
178 if (copy)
179 arg.append(args[p]);
180 ++p;
181 }
182 }
183 //not reached
184}
185
186QString KShell::quoteArgInternal(const QString &arg, bool _inquote)
187{
188 // Escape quotes, preceding backslashes are doubled. Surround with quotes.
189 // Note that cmd does not understand quote escapes in quoted strings,
190 // so the quoting needs to be "suspended".
191 const QLatin1Char bs('\\'), dq('\"');
192 QString ret;
193 bool inquote = _inquote;
194 int bslashes = 0;
195 for (int p = 0; p < arg.length(); p++) {
196 if (arg[p] == bs) {
197 bslashes++;
198 } else if (arg[p] == dq) {
199 if (inquote) {
200 ret.append(dq);
201 inquote = false;
202 }
203 for (; bslashes; bslashes--)
204 ret.append(QLatin1String("\\\\"));
205 ret.append(QLatin1String("\\^\""));
206 } else {
207 if (!inquote) {
208 ret.append(dq);
209 inquote = true;
210 }
211 for (; bslashes; bslashes--)
212 ret.append(bs);
213 ret.append(arg[p]);
214 }
215 }
216 ret.replace(QLatin1Char('%'), PERCENT_ESCAPE);
217 if (bslashes) {
218 // Ensure that we don't have directly trailing backslashes,
219 // so concatenating with another string won't cause surprises.
220 if (!inquote && !_inquote)
221 ret.append(dq);
222 for (; bslashes; bslashes--)
223 ret.append(QLatin1String("\\\\"));
224 ret.append(dq);
225 if (inquote && _inquote)
226 ret.append(dq);
227 } else if (inquote != _inquote) {
228 ret.append(dq);
229 }
230 return ret;
231}
232
233QString KShell::quoteArg(const QString &arg)
234{
235 if (arg.isEmpty())
236 return QString::fromLatin1("\"\"");
237
238 // Ensure that we don't have directly trailing backslashes,
239 // so concatenating with another string won't cause surprises.
240 if (arg.endsWith(QLatin1Char('\\')))
241 return quoteArgInternal(arg, false);
242
243 for (int x = arg.length() - 1; x >= 0; --x)
244 if (isSpecialChar(arg[x].unicode()))
245 return quoteArgInternal(arg, false);
246
247 // Escape quotes. Preceding backslashes are doubled.
248 // Note that the remaining string is not quoted.
249 QString ret(arg);
250 ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\^\""));
251 ret.replace(QLatin1Char('%'), PERCENT_ESCAPE);
252 return ret;
253}
254
QStringList
QString
kkernel_win.h
kshell.h
kshell_p.h
PERCENT_ESCAPE
#define PERCENT_ESCAPE
Definition: kshell_p.h:35
isMetaChar
static bool isMetaChar(ushort c)
Definition: kshell_win.cpp:58
isSpecialChar
static bool isSpecialChar(ushort c)
Definition: kshell_win.cpp:68
isWhiteSpace
static bool isWhiteSpace(ushort c)
Definition: kshell_win.cpp:82
KShell::quoteArgInternal
QString quoteArgInternal(const QString &arg, bool _inquote)
Definition: kshell_win.cpp:186
KShell::quoteArg
QString quoteArg(const QString &arg)
Quotes arg according to system shell rules.
Definition: kshell_unix.cpp:285
KShell::splitArgs
QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=0)
Splits cmd according to system shell word splitting and quoting rules.
Definition: kshell_unix.cpp:70
KShell::BadQuoting
@ BadQuoting
Indicates a parsing error, like an unterminated quoted string.
Definition: kshell.h:94
KShell::FoundMeta
@ FoundMeta
The AbortOnMeta flag was set and an unhandled shell meta character was encoutered.
Definition: kshell.h:100
KShell::NoError
@ NoError
Success.
Definition: kshell.h:89
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal