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 
16  : d(new KMacroExpanderBasePrivate(c))
17 {
18 }
19 
21 
23 {
24  d->escapechar = c;
25 }
26 
28 {
29  return d->escapechar;
30 }
31 
33 {
34  int pos;
35  int len;
36  ushort ec = d->escapechar.unicode();
37  QStringList rst;
38  QString rsts;
39 
40  for (pos = 0; pos < str.length();) {
41  if (ec != 0) {
42  if (str.unicode()[pos].unicode() != ec) {
43  goto nohit;
44  }
45  if (!(len = expandEscapedMacro(str, pos, rst))) {
46  goto nohit;
47  }
48  } else {
49  if (!(len = expandPlainMacro(str, pos, rst))) {
50  goto nohit;
51  }
52  }
53  if (len < 0) {
54  pos -= len;
55  continue;
56  }
57  rsts = rst.join(QLatin1Char(' '));
58  rst.clear();
59  str.replace(pos, len, rsts);
60  pos += rsts.length();
61  continue;
62  nohit:
63  pos++;
64  }
65 }
66 
68 {
69  int pos = 0;
70  return expandMacrosShellQuote(str, pos) && pos == str.length();
71 }
72 
74 {
75  qFatal("KMacroExpanderBase::expandPlainMacro called!");
76  return 0;
77 }
78 
80 {
81  qFatal("KMacroExpanderBase::expandEscapedMacro called!");
82  return 0;
83 }
84 
85 //////////////////////////////////////////////////
86 
87 template<typename KT, typename VT>
88 class KMacroMapExpander : public KMacroExpanderBase
89 {
90 public:
91  KMacroMapExpander(const QHash<KT, VT> &map, QChar c = QLatin1Char('%'))
93  , macromap(map)
94  {
95  }
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 
113 ////////
114 
115 static bool isIdentifier(ushort c)
116 {
117  return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
118 }
119 
120 ////////
121 
122 template<typename VT>
123 class KMacroMapExpander<QChar, VT> : public KMacroExpanderBase
124 {
125 public:
126  KMacroMapExpander(const QHash<QChar, VT> &map, QChar c = QLatin1Char('%'))
127  : KMacroExpanderBase(c)
128  , macromap(map)
129  {
130  }
131 
132 protected:
133  int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
134  int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
135 
136 private:
137  QHash<QChar, VT> macromap;
138 };
139 
140 template<typename VT>
141 int KMacroMapExpander<QChar, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret)
142 {
143  typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos]);
144  if (it != macromap.constEnd()) {
145  ret += it.value();
146  return 1;
147  }
148  return 0;
149 }
150 
151 template<typename VT>
152 int KMacroMapExpander<QChar, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
153 {
154  if (str.length() <= pos + 1) {
155  return 0;
156  }
157 
158  if (str.unicode()[pos + 1] == escapeChar()) {
159  ret += QString(escapeChar());
160  return 2;
161  }
162  typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos + 1]);
163  if (it != macromap.constEnd()) {
164  ret += it.value();
165  return 2;
166  }
167 
168  return 0;
169 }
170 
171 template<typename VT>
172 class KMacroMapExpander<QString, VT> : public KMacroExpanderBase
173 {
174 public:
175  KMacroMapExpander(const QHash<QString, VT> &map, QChar c = QLatin1Char('%'))
176  : KMacroExpanderBase(c)
177  , macromap(map)
178  {
179  }
180 
181 protected:
182  int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
183  int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
184 
185 private:
186  QHash<QString, VT> macromap;
187 };
188 
189 template<typename VT>
190 int KMacroMapExpander<QString, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret)
191 {
192  if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) {
193  return 0;
194  }
195  int sl;
196  for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++)
197  ;
198  if (!sl) {
199  return 0;
200  }
201  typename QHash<QString, VT>::const_iterator it = macromap.constFind(str.mid(pos, sl));
202  if (it != macromap.constEnd()) {
203  ret += it.value();
204  return sl;
205  }
206  return 0;
207 }
208 
209 template<typename VT>
210 int KMacroMapExpander<QString, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
211 {
212  if (str.length() <= pos + 1) {
213  return 0;
214  }
215 
216  if (str.unicode()[pos + 1] == escapeChar()) {
217  ret += QString(escapeChar());
218  return 2;
219  }
220  int sl, rsl, rpos;
221  if (str.unicode()[pos + 1].unicode() == '{') {
222  rpos = pos + 2;
223  if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) {
224  return 0;
225  }
226  sl -= rpos;
227  rsl = sl + 3;
228  } else {
229  rpos = pos + 1;
230  for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl)
231  ;
232  rsl = sl + 1;
233  }
234  if (!sl) {
235  return 0;
236  }
237  typename QHash<QString, VT>::const_iterator it = macromap.constFind(str.mid(rpos, sl));
238  if (it != macromap.constEnd()) {
239  ret += it.value();
240  return rsl;
241  }
242  return 0;
243 }
244 
245 ////////////
246 
247 int KCharMacroExpander::expandPlainMacro(const QString &str, int pos, QStringList &ret)
248 {
249  if (expandMacro(str.unicode()[pos], ret)) {
250  return 1;
251  }
252  return 0;
253 }
254 
255 int KCharMacroExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
256 {
257  if (str.length() <= pos + 1) {
258  return 0;
259  }
260 
261  if (str.unicode()[pos + 1] == escapeChar()) {
262  ret += QString(escapeChar());
263  return 2;
264  }
265  if (expandMacro(str.unicode()[pos + 1], ret)) {
266  return 2;
267  }
268  return 0;
269 }
270 
271 int KWordMacroExpander::expandPlainMacro(const QString &str, int pos, QStringList &ret)
272 {
273  if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) {
274  return 0;
275  }
276  int sl;
277  for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++)
278  ;
279  if (!sl) {
280  return 0;
281  }
282  if (expandMacro(str.mid(pos, sl), ret)) {
283  return sl;
284  }
285  return 0;
286 }
287 
288 int KWordMacroExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
289 {
290  if (str.length() <= pos + 1) {
291  return 0;
292  }
293 
294  if (str.unicode()[pos + 1] == escapeChar()) {
295  ret += QString(escapeChar());
296  return 2;
297  }
298  int sl, rsl, rpos;
299  if (str.unicode()[pos + 1].unicode() == '{') {
300  rpos = pos + 2;
301  if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) {
302  return 0;
303  }
304  sl -= rpos;
305  rsl = sl + 3;
306  } else {
307  rpos = pos + 1;
308  for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl)
309  ;
310  rsl = sl + 1;
311  }
312  if (!sl) {
313  return 0;
314  }
315  if (expandMacro(str.mid(rpos, sl), ret)) {
316  return rsl;
317  }
318  return 0;
319 }
320 
321 ////////////
322 
323 template<typename KT, typename VT>
324 inline QString TexpandMacros(const QString &ostr, const QHash<KT, VT> &map, QChar c)
325 {
326  QString str(ostr);
327  KMacroMapExpander<KT, VT> kmx(map, c);
328  kmx.expandMacros(str);
329  return str;
330 }
331 
332 template<typename KT, typename VT>
333 inline QString TexpandMacrosShellQuote(const QString &ostr, const QHash<KT, VT> &map, QChar c)
334 {
335  QString str(ostr);
336  KMacroMapExpander<KT, VT> kmx(map, c);
337  if (!kmx.expandMacrosShellQuote(str)) {
338  return QString();
339  }
340  return str;
341 }
342 
343 // public API
344 namespace KMacroExpander
345 {
346 QString expandMacros(const QString &ostr, const QHash<QChar, QString> &map, QChar c)
347 {
348  return TexpandMacros(ostr, map, c);
349 }
350 QString expandMacrosShellQuote(const QString &ostr, const QHash<QChar, QString> &map, QChar c)
351 {
352  return TexpandMacrosShellQuote(ostr, map, c);
353 }
354 QString expandMacros(const QString &ostr, const QHash<QString, QString> &map, QChar c)
355 {
356  return TexpandMacros(ostr, map, c);
357 }
358 QString expandMacrosShellQuote(const QString &ostr, const QHash<QString, QString> &map, QChar c)
359 {
360  return TexpandMacrosShellQuote(ostr, map, c);
361 }
362 QString expandMacros(const QString &ostr, const QHash<QChar, QStringList> &map, QChar c)
363 {
364  return TexpandMacros(ostr, map, c);
365 }
366 QString expandMacrosShellQuote(const QString &ostr, const QHash<QChar, QStringList> &map, QChar c)
367 {
368  return TexpandMacrosShellQuote(ostr, map, c);
369 }
370 QString expandMacros(const QString &ostr, const QHash<QString, QStringList> &map, QChar c)
371 {
372  return TexpandMacros(ostr, map, c);
373 }
374 QString expandMacrosShellQuote(const QString &ostr, const QHash<QString, QStringList> &map, QChar c)
375 {
376  return TexpandMacrosShellQuote(ostr, map, c);
377 }
378 
379 } // 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-2021 The KDE developers.
Generated on Fri Apr 9 2021 23:01:38 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.