KCoreAddons

kshell_unix.cpp
1 /*
2  This file is part of the KDE libraries
3 
4  SPDX-FileCopyrightText: 2003, 2007 Oswald Buddenhagen <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "kshell.h"
10 #include "kshell_p.h"
11 
12 #include <kuser.h>
13 
14 #include <QChar>
15 #include <QStringList>
16 
17 static int fromHex(QChar cUnicode)
18 {
19  char c = cUnicode.toLatin1();
20 
21  if (c >= '0' && c <= '9') {
22  return c - '0';
23  } else if (c >= 'A' && c <= 'F') {
24  return c - 'A' + 10;
25  } else if (c >= 'a' && c <= 'f') {
26  return c - 'a' + 10;
27  }
28  return -1;
29 }
30 
31 inline static bool isQuoteMeta(QChar cUnicode)
32 {
33 #if 0 // it's not worth it, especially after seeing gcc's asm output ...
34  static const uchar iqm[] = {
35  0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
36  0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00
37  }; // \'"$
38 
39  return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
40 #else
41  char c = cUnicode.toLatin1();
42  return c == '\\' || c == '\'' || c == '"' || c == '$';
43 #endif
44 }
45 
46 inline static bool isMeta(QChar cUnicode)
47 {
48  static const uchar iqm[] = {
49  0x00, 0x00, 0x00, 0x00, 0xdc, 0x07, 0x00, 0xd8,
50  0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x38
51  }; // \'"$`<>|;&(){}*?#[]
52 
53  uint c = cUnicode.unicode();
54 
55  return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
56 }
57 
59 {
60  QStringList ret;
61  bool firstword = flags & AbortOnMeta;
62 
63  for (int pos = 0;;) {
64  QChar c;
65  do {
66  if (pos >= args.length()) {
67  goto okret;
68  }
69  c = args.unicode()[pos++];
70  } while (c == QLatin1Char(' '));
71  QString cret;
72  if ((flags & TildeExpand) && c == QLatin1Char('~')) {
73  int opos = pos;
74  for (;; pos++) {
75  if (pos >= args.length()) {
76  break;
77  }
78  c = args.unicode()[pos];
79  if (c == QLatin1Char('/') || c == QLatin1Char(' ')) {
80  break;
81  }
82  if (isQuoteMeta(c)) {
83  pos = opos;
84  c = QLatin1Char('~');
85  goto notilde;
86  }
87  if ((flags & AbortOnMeta) && isMeta(c)) {
88  goto metaerr;
89  }
90  }
91  QString ccret = homeDir(args.mid(opos, pos - opos));
92  if (ccret.isEmpty()) {
93  pos = opos;
94  c = QLatin1Char('~');
95  goto notilde;
96  }
97  if (pos >= args.length()) {
98  ret += ccret;
99  goto okret;
100  }
101  pos++;
102  if (c == QLatin1Char(' ')) {
103  ret += ccret;
104  firstword = false;
105  continue;
106  }
107  cret = ccret;
108  }
109  // before the notilde label, as a tilde does not match anyway
110  if (firstword) {
111  if (c == QLatin1Char('_') ||
112  (c >= QLatin1Char('A') && c <= QLatin1Char('Z')) ||
113  (c >= QLatin1Char('a') && c <= QLatin1Char('z'))) {
114  int pos2 = pos;
115  QChar cc;
116  do {
117  if (pos2 >= args.length()) {
118  // Exactly one word
119  ret += args.mid(pos - 1);
120  goto okret;
121  }
122  cc = args.unicode()[pos2++];
123  } while (cc == QLatin1Char('_') ||
124  (cc >= QLatin1Char('A') && cc <= QLatin1Char('Z')) ||
125  (cc >= QLatin1Char('a') && cc <= QLatin1Char('z')) ||
126  (cc >= QLatin1Char('0') && cc <= QLatin1Char('9')));
127  if (cc == QLatin1Char('=')) {
128  goto metaerr;
129  }
130  }
131  }
132  notilde:
133  do {
134  if (c == QLatin1Char('\'')) {
135  int spos = pos;
136  do {
137  if (pos >= args.length()) {
138  goto quoteerr;
139  }
140  c = args.unicode()[pos++];
141  } while (c != QLatin1Char('\''));
142  cret += args.midRef(spos, pos - spos - 1);
143  } else if (c == QLatin1Char('"')) {
144  for (;;) {
145  if (pos >= args.length()) {
146  goto quoteerr;
147  }
148  c = args.unicode()[pos++];
149  if (c == QLatin1Char('"')) {
150  break;
151  }
152  if (c == QLatin1Char('\\')) {
153  if (pos >= args.length()) {
154  goto quoteerr;
155  }
156  c = args.unicode()[pos++];
157  if (c != QLatin1Char('"') &&
158  c != QLatin1Char('\\') &&
159  !((flags & AbortOnMeta) &&
160  (c == QLatin1Char('$') ||
161  c == QLatin1Char('`')))) {
162  cret += QLatin1Char('\\');
163  }
164  } else if ((flags & AbortOnMeta) &&
165  (c == QLatin1Char('$') ||
166  c == QLatin1Char('`'))) {
167  goto metaerr;
168  }
169  cret += c;
170  }
171  } else if (c == QLatin1Char('$') && pos < args.length() &&
172  args.unicode()[pos] == QLatin1Char('\'')) {
173  pos++;
174  for (;;) {
175  if (pos >= args.length()) {
176  goto quoteerr;
177  }
178  c = args.unicode()[pos++];
179  if (c == QLatin1Char('\'')) {
180  break;
181  }
182  if (c == QLatin1Char('\\')) {
183  if (pos >= args.length()) {
184  goto quoteerr;
185  }
186  c = args.unicode()[pos++];
187  switch (c.toLatin1()) {
188  case 'a': cret += QLatin1Char('\a'); break;
189  case 'b': cret += QLatin1Char('\b'); break;
190  case 'e': cret += QLatin1Char('\033'); break;
191  case 'f': cret += QLatin1Char('\f'); break;
192  case 'n': cret += QLatin1Char('\n'); break;
193  case 'r': cret += QLatin1Char('\r'); break;
194  case 't': cret += QLatin1Char('\t'); break;
195  case '\\': cret += QLatin1Char('\\'); break;
196  case '\'': cret += QLatin1Char('\''); break;
197  case 'c':
198  if (pos >= args.length()) {
199  goto quoteerr;
200  }
201  cret += args.unicode()[pos++].toLatin1() & 31;
202  break;
203  case 'x': {
204  if (pos >= args.length()) {
205  goto quoteerr;
206  }
207  int hv = fromHex(args.unicode()[pos++]);
208  if (hv < 0) {
209  goto quoteerr;
210  }
211  if (pos < args.length()) {
212  int hhv = fromHex(args.unicode()[pos]);
213  if (hhv > 0) {
214  hv = hv * 16 + hhv;
215  pos++;
216  }
217  cret += QChar(hv);
218  }
219  break;
220  }
221  default:
222  if (c.toLatin1() >= '0' && c.toLatin1() <= '7') {
223  char cAscii = c.toLatin1();
224  int hv = cAscii - '0';
225  for (int i = 0; i < 2; i++) {
226  if (pos >= args.length()) {
227  break;
228  }
229  c = args.unicode()[pos];
230  if (c.toLatin1() < '0' || c.toLatin1() > '7') {
231  break;
232  }
233  hv = hv * 8 + (c.toLatin1() - '0');
234  pos++;
235  }
236  cret += QChar(hv);
237  } else {
238  cret += QLatin1Char('\\');
239  cret += c;
240  }
241  break;
242  }
243  } else {
244  cret += c;
245  }
246  }
247  } else {
248  if (c == QLatin1Char('\\')) {
249  if (pos >= args.length()) {
250  goto quoteerr;
251  }
252  c = args.unicode()[pos++];
253  } else if ((flags & AbortOnMeta) && isMeta(c)) {
254  goto metaerr;
255  }
256  cret += c;
257  }
258  if (pos >= args.length()) {
259  break;
260  }
261  c = args.unicode()[pos++];
262  } while (c != QLatin1Char(' '));
263  ret += cret;
264  firstword = false;
265  }
266 
267 okret:
268  if (err) {
269  *err = NoError;
270  }
271  return ret;
272 
273 quoteerr:
274  if (err) {
275  *err = BadQuoting;
276  }
277  return QStringList();
278 
279 metaerr:
280  if (err) {
281  *err = FoundMeta;
282  }
283  return QStringList();
284 }
285 
286 inline static bool isSpecial(QChar cUnicode)
287 {
288  static const uchar iqm[] = {
289  0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
290  0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
291  }; // 0-32 \'"$`<>|;&(){}*?#!~[]
292 
293  uint c = cUnicode.unicode();
294  return ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))));
295 }
296 
298 {
299  if (!arg.length()) {
300  return QStringLiteral("''");
301  }
302  for (int i = 0; i < arg.length(); i++)
303  if (isSpecial(arg.unicode()[i])) {
304  QChar q(QLatin1Char('\''));
305  return q + QString(arg).replace(q, QLatin1String("'\\''")) + q;
306  }
307  return arg;
308 }
The AbortOnMeta flag was set and an unhandled shell meta character was encountered.
Definition: kshell.h:93
bool isEmpty() const const
Errors
Status codes from splitArgs()
Definition: kshell.h:78
KCOREADDONS_EXPORT QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=nullptr)
Splits cmd according to system shell word splitting and quoting rules.
Definition: kshell_unix.cpp:58
ushort unicode() const const
KCOREADDONS_EXPORT QString quoteArg(const QString &arg)
Quotes arg according to system shell rules.
QStringRef midRef(int position, int n) const const
char toLatin1() const const
QString & replace(int position, int n, QChar after)
const QChar * unicode() const const
QString mid(int position, int n) const const
Indicates a parsing error, like an unterminated quoted string.
Definition: kshell.h:87
int length() const const
Put the parser into full shell mode and bail out if a too complex construct is encountered.
Definition: kshell.h:68
Perform tilde expansion.
Definition: kshell.h:37
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Aug 3 2020 23:01:25 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.