KCoreAddons

kmacroexpander.cpp
1 /*
2  This file is part of the KDE libraries
3 
4  SPDX-FileCopyrightText: 2002-2003 Oswald Buddenhagen <[email protected]>
5  SPDX-FileCopyrightText: 2003 Waldo Bastian <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 
10 #include "kmacroexpander_p.h"
11 
12 #include <QHash>
13 #include <QStringList>
14 
15 KMacroExpanderBase::KMacroExpanderBase(QChar c) : d(new KMacroExpanderBasePrivate(c))
16 {
17 }
18 
20 {
21  delete d;
22 }
23 
25 {
26  d->escapechar = c;
27 }
28 
30 {
31  return d->escapechar;
32 }
33 
35 {
36  int pos;
37  int len;
38  ushort ec = d->escapechar.unicode();
39  QStringList rst;
40  QString rsts;
41 
42  for (pos = 0; pos < str.length();) {
43  if (ec != 0) {
44  if (str.unicode()[pos].unicode() != ec) {
45  goto nohit;
46  }
47  if (!(len = expandEscapedMacro(str, pos, rst))) {
48  goto nohit;
49  }
50  } else {
51  if (!(len = expandPlainMacro(str, pos, rst))) {
52  goto nohit;
53  }
54  }
55  if (len < 0) {
56  pos -= len;
57  continue;
58  }
59  rsts = rst.join(QLatin1Char(' '));
60  rst.clear();
61  str.replace(pos, len, rsts);
62  pos += rsts.length();
63  continue;
64  nohit:
65  pos++;
66  }
67 }
68 
70 {
71  int pos = 0;
72  return expandMacrosShellQuote(str, pos) && pos == str.length();
73 }
74 
76 {
77  qFatal("KMacroExpanderBase::expandPlainMacro called!");
78  return 0;
79 }
80 
82 {
83  qFatal("KMacroExpanderBase::expandEscapedMacro called!");
84  return 0;
85 }
86 
88 
89 template <typename KT, typename VT>
90 class KMacroMapExpander : public KMacroExpanderBase
91 {
92 
93 public:
94  KMacroMapExpander(const QHash<KT, VT> &map, QChar c = QLatin1Char('%')) :
95  KMacroExpanderBase(c), macromap(map) {}
96 
97 protected:
98  int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
99  int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
100 
101 private:
102  QHash<KT, VT> macromap;
103 };
104 
105 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
106 static QStringList &operator+=(QStringList &s, const QString &n)
107 {
108  s << n;
109  return s;
110 }
111 #endif
112 
114 
115 static bool
116 isIdentifier(ushort c)
117 {
118  return c == '_' ||
119  (c >= 'A' && c <= 'Z') ||
120  (c >= 'a' && c <= 'z') ||
121  (c >= '0' && c <= '9');
122 }
123 
125 
126 template <typename VT>
127 class KMacroMapExpander<QChar, VT> : public KMacroExpanderBase
128 {
129 
130 public:
131  KMacroMapExpander(const QHash<QChar, VT> &map, QChar c = QLatin1Char('%')) :
132  KMacroExpanderBase(c), macromap(map) {}
133 
134 protected:
135  int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
136  int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
137 
138 private:
139  QHash<QChar, VT> macromap;
140 };
141 
142 template <typename VT>
143 int
144 KMacroMapExpander<QChar, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret)
145 {
146  typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos]);
147  if (it != macromap.constEnd()) {
148  ret += it.value();
149  return 1;
150  }
151  return 0;
152 }
153 
154 template <typename VT>
155 int
156 KMacroMapExpander<QChar, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
157 {
158  if (str.length() <= pos + 1) {
159  return 0;
160  }
161 
162  if (str.unicode()[pos + 1] == escapeChar()) {
163  ret += QString(escapeChar());
164  return 2;
165  }
166  typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos + 1]);
167  if (it != macromap.constEnd()) {
168  ret += it.value();
169  return 2;
170  }
171 
172  return 0;
173 }
174 
175 template <typename VT>
176 class KMacroMapExpander<QString, VT> : public KMacroExpanderBase
177 {
178 
179 public:
180  KMacroMapExpander(const QHash<QString, VT> &map, QChar c = QLatin1Char('%')) :
181  KMacroExpanderBase(c), macromap(map) {}
182 
183 protected:
184  int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
185  int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
186 
187 private:
188  QHash<QString, VT> macromap;
189 };
190 
191 template <typename VT>
192 int
193 KMacroMapExpander<QString, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret)
194 {
195  if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) {
196  return 0;
197  }
198  int sl;
199  for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++)
200  ;
201  if (!sl) {
202  return 0;
203  }
205  macromap.constFind(str.mid(pos, sl));
206  if (it != macromap.constEnd()) {
207  ret += it.value();
208  return sl;
209  }
210  return 0;
211 }
212 
213 template <typename VT>
214 int
215 KMacroMapExpander<QString, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
216 {
217  if (str.length() <= pos + 1) {
218  return 0;
219  }
220 
221  if (str.unicode()[pos + 1] == escapeChar()) {
222  ret += QString(escapeChar());
223  return 2;
224  }
225  int sl, rsl, rpos;
226  if (str.unicode()[pos + 1].unicode() == '{') {
227  rpos = pos + 2;
228  if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) {
229  return 0;
230  }
231  sl -= rpos;
232  rsl = sl + 3;
233  } else {
234  rpos = pos + 1;
235  for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl)
236  ;
237  rsl = sl + 1;
238  }
239  if (!sl) {
240  return 0;
241  }
243  macromap.constFind(str.mid(rpos, sl));
244  if (it != macromap.constEnd()) {
245  ret += it.value();
246  return rsl;
247  }
248  return 0;
249 }
250 
252 
253 int
254 KCharMacroExpander::expandPlainMacro(const QString &str, int pos, QStringList &ret)
255 {
256  if (expandMacro(str.unicode()[pos], ret)) {
257  return 1;
258  }
259  return 0;
260 }
261 
262 int
263 KCharMacroExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
264 {
265  if (str.length() <= pos + 1) {
266  return 0;
267  }
268 
269  if (str.unicode()[pos + 1] == escapeChar()) {
270  ret += QString(escapeChar());
271  return 2;
272  }
273  if (expandMacro(str.unicode()[pos + 1], ret)) {
274  return 2;
275  }
276  return 0;
277 }
278 
279 int
280 KWordMacroExpander::expandPlainMacro(const QString &str, int pos, QStringList &ret)
281 {
282  if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) {
283  return 0;
284  }
285  int sl;
286  for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++)
287  ;
288  if (!sl) {
289  return 0;
290  }
291  if (expandMacro(str.mid(pos, sl), ret)) {
292  return sl;
293  }
294  return 0;
295 }
296 
297 int
298 KWordMacroExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
299 {
300  if (str.length() <= pos + 1) {
301  return 0;
302  }
303 
304  if (str.unicode()[pos + 1] == escapeChar()) {
305  ret += QString(escapeChar());
306  return 2;
307  }
308  int sl, rsl, rpos;
309  if (str.unicode()[pos + 1].unicode() == '{') {
310  rpos = pos + 2;
311  if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) {
312  return 0;
313  }
314  sl -= rpos;
315  rsl = sl + 3;
316  } else {
317  rpos = pos + 1;
318  for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl)
319  ;
320  rsl = sl + 1;
321  }
322  if (!sl) {
323  return 0;
324  }
325  if (expandMacro(str.mid(rpos, sl), ret)) {
326  return rsl;
327  }
328  return 0;
329 }
330 
332 
333 template <typename KT, typename VT>
334 inline QString
335 TexpandMacros(const QString &ostr, const QHash<KT, VT> &map, QChar c)
336 {
337  QString str(ostr);
338  KMacroMapExpander<KT, VT> kmx(map, c);
339  kmx.expandMacros(str);
340  return str;
341 }
342 
343 template <typename KT, typename VT>
344 inline QString
345 TexpandMacrosShellQuote(const QString &ostr, const QHash<KT, VT> &map, QChar c)
346 {
347  QString str(ostr);
348  KMacroMapExpander<KT, VT> kmx(map, c);
349  if (!kmx.expandMacrosShellQuote(str)) {
350  return QString();
351  }
352  return str;
353 }
354 
355 // public API
356 namespace KMacroExpander
357 {
358 
359 QString expandMacros(const QString &ostr, const QHash<QChar, QString> &map, QChar c)
360 {
361  return TexpandMacros(ostr, map, c);
362 }
363 QString expandMacrosShellQuote(const QString &ostr, const QHash<QChar, QString> &map, QChar c)
364 {
365  return TexpandMacrosShellQuote(ostr, map, c);
366 }
367 QString expandMacros(const QString &ostr, const QHash<QString, QString> &map, QChar c)
368 {
369  return TexpandMacros(ostr, map, c);
370 }
371 QString expandMacrosShellQuote(const QString &ostr, const QHash<QString, QString> &map, QChar c)
372 {
373  return TexpandMacrosShellQuote(ostr, map, c);
374 }
375 QString expandMacros(const QString &ostr, const QHash<QChar, QStringList> &map, QChar c)
376 {
377  return TexpandMacros(ostr, map, c);
378 }
379 QString expandMacrosShellQuote(const QString &ostr, const QHash<QChar, QStringList> &map, QChar c)
380 {
381  return TexpandMacrosShellQuote(ostr, map, c);
382 }
383 QString expandMacros(const QString &ostr, const QHash<QString, QStringList> &map, QChar c)
384 {
385  return TexpandMacros(ostr, map, c);
386 }
387 QString expandMacrosShellQuote(const QString &ostr, const QHash<QString, QStringList> &map, QChar c)
388 {
389  return TexpandMacrosShellQuote(ostr, map, c);
390 }
391 
392 } // namespace
void clear()
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
void expandMacros(QString &str)
Perform safe macro expansion (substitution) on a string.
Abstract base class for the worker classes behind the KMacroExpander namespace and the KCharMacroExpa...
KMacroExpanderBase(QChar c=QLatin1Char('%'))
Constructor.
bool expandMacrosShellQuote(QString &str, int &pos)
Perform safe macro expansion (substitution) on a string for use in shell commands.
virtual ~KMacroExpanderBase()
Destructor.
QHash::const_iterator constFind(const Key &key) const const
QString join(const QString &separator) const const
void setEscapeChar(QChar c)
Set the macro escape character.
virtual int expandEscapedMacro(const QString &str, int pos, QStringList &ret)
This function is called every time the escape char is found if it is not QChar::null.
virtual int expandPlainMacro(const QString &str, int pos, QStringList &ret)
This function is called for every single char within the string if the escape char is QChar::null...
int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override
ushort unicode() const const
A group of functions providing macro expansion (substitution) in strings, optionally with quoting app...
int expandPlainMacro(const QString &str, int pos, QStringList &ret) override
QString & replace(int position, int n, QChar after)
const QChar * unicode() const const
QString mid(int position, int n) const const
QChar escapeChar() const
Obtain the macro escape character.
int expandPlainMacro(const QString &str, int pos, QStringList &ret) override
int length() const const
int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat May 30 2020 23:10:51 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.