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

KDE's Doxygen guidelines are available online.