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

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • 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 
58 inline 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 
68 inline 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 
82 inline static bool isWhiteSpace(ushort c)
83 {
84  return c == ' ' || c == '\t';
85 }
86 
87 QStringList 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 
186 QString 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 
233 QString 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 
isSpecialChar
static bool isSpecialChar(ushort c)
Definition: kshell_win.cpp:68
kshell_p.h
QString::append
QString & append(QChar ch)
PERCENT_ESCAPE
#define PERCENT_ESCAPE
Definition: kshell_p.h:35
kshell.h
QString::remove
QString & remove(int position, int n)
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
QRegExp
QList::append
void append(const T &value)
KShell::FoundMeta
The AbortOnMeta flag was set and an unhandled shell meta character was encoutered.
Definition: kshell.h:100
isWhiteSpace
static bool isWhiteSpace(ushort c)
Definition: kshell_win.cpp:82
QString::isEmpty
bool isEmpty() const
KShell::Errors
Errors
Status codes from splitArgs()
Definition: kshell.h:85
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
QString
QStringList
kkernel_win.h
KShell::quoteArg
QString quoteArg(const QString &arg)
Quotes arg according to system shell rules.
Definition: kshell_unix.cpp:285
QLatin1Char
QString::replace
QString & replace(int position, int n, QChar after)
QString::unicode
const QChar * unicode() const
QLatin1String
KShell::BadQuoting
Indicates a parsing error, like an unterminated quoted string.
Definition: kshell.h:94
KShell::NoError
Success.
Definition: kshell.h:89
QString::length
int length() const
KShell::quoteArgInternal
QString quoteArgInternal(const QString &arg, bool _inquote)
Definition: kshell_win.cpp:186
QString::fromLatin1
QString fromLatin1(const char *str, int size)
isMetaChar
static bool isMetaChar(ushort c)
Definition: kshell_win.cpp:58
KShell::AbortOnMeta
Put the parser into full shell mode and bail out if a too complex construct is encoutered.
Definition: kshell.h:78
QList::replace
void replace(int i, const T &value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:11 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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

Search



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