KCoreAddons

kmacroexpander.cpp
1/*
2 This file is part of the KDE libraries
3
4 SPDX-FileCopyrightText: 2002-2003 Oswald Buddenhagen <ossi@kde.org>
5 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
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
86template<typename KT, typename VT>
87class KMacroMapExpander : public KMacroExpanderBase
88{
89public:
90 KMacroMapExpander(const QHash<KT, VT> &map, QChar c = QLatin1Char('%'))
92 , macromap(map)
93 {
94 }
95
96protected:
97 int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
98 int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
99
100private:
101 QHash<KT, VT> macromap;
102};
103
104////////
105
106static bool isIdentifier(ushort c)
107{
108 return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
109}
110
111////////
112
113template<typename VT>
114class KMacroMapExpander<QChar, VT> : public KMacroExpanderBase
115{
116public:
117 KMacroMapExpander(const QHash<QChar, VT> &map, QChar c = QLatin1Char('%'))
119 , macromap(map)
120 {
121 }
122
123protected:
124 int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
125 int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
126
127private:
128 QHash<QChar, VT> macromap;
129};
130
131template<typename VT>
132int KMacroMapExpander<QChar, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret)
133{
134 typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos]);
135 if (it != macromap.constEnd()) {
136 ret += it.value();
137 return 1;
138 }
139 return 0;
140}
141
142template<typename VT>
143int KMacroMapExpander<QChar, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
144{
145 if (str.length() <= pos + 1) {
146 return 0;
147 }
148
149 if (str.unicode()[pos + 1] == escapeChar()) {
150 ret += QString(escapeChar());
151 return 2;
152 }
153 typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos + 1]);
154 if (it != macromap.constEnd()) {
155 ret += it.value();
156 return 2;
157 }
158
159 return 0;
160}
161
162template<typename VT>
163class KMacroMapExpander<QString, VT> : public KMacroExpanderBase
164{
165public:
166 KMacroMapExpander(const QHash<QString, VT> &map, QChar c = QLatin1Char('%'))
168 , macromap(map)
169 {
170 }
171
172protected:
173 int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
174 int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
175
176private:
177 QHash<QString, VT> macromap;
178};
179
180template<typename VT>
181int KMacroMapExpander<QString, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret)
182{
183 if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) {
184 return 0;
185 }
186 int sl;
187 for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++) {
188 ;
189 }
190 if (!sl) {
191 return 0;
192 }
193 typename QHash<QString, VT>::const_iterator it = macromap.constFind(str.mid(pos, sl));
194 if (it != macromap.constEnd()) {
195 ret += it.value();
196 return sl;
197 }
198 return 0;
199}
200
201template<typename VT>
202int KMacroMapExpander<QString, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
203{
204 if (str.length() <= pos + 1) {
205 return 0;
206 }
207
208 if (str.unicode()[pos + 1] == escapeChar()) {
209 ret += QString(escapeChar());
210 return 2;
211 }
212 int sl;
213 int rsl;
214 int rpos;
215 if (str.unicode()[pos + 1].unicode() == '{') {
216 rpos = pos + 2;
217 if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) {
218 return 0;
219 }
220 sl -= rpos;
221 rsl = sl + 3;
222 } else {
223 rpos = pos + 1;
224 for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl) {
225 ;
226 }
227 rsl = sl + 1;
228 }
229 if (!sl) {
230 return 0;
231 }
232 typename QHash<QString, VT>::const_iterator it = macromap.constFind(str.mid(rpos, sl));
233 if (it != macromap.constEnd()) {
234 ret += it.value();
235 return rsl;
236 }
237 return 0;
238}
239
240////////////
241
243{
244 if (expandMacro(str.unicode()[pos], ret)) {
245 return 1;
246 }
247 return 0;
248}
249
251{
252 if (str.length() <= pos + 1) {
253 return 0;
254 }
255
256 if (str.unicode()[pos + 1] == escapeChar()) {
257 ret += QString(escapeChar());
258 return 2;
259 }
260 if (expandMacro(str.unicode()[pos + 1], ret)) {
261 return 2;
262 }
263 return 0;
264}
265
267{
268 if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) {
269 return 0;
270 }
271 int sl;
272 for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++) {
273 ;
274 }
275 if (!sl) {
276 return 0;
277 }
278 if (expandMacro(str.mid(pos, sl), ret)) {
279 return sl;
280 }
281 return 0;
282}
283
285{
286 if (str.length() <= pos + 1) {
287 return 0;
288 }
289
290 if (str.unicode()[pos + 1] == escapeChar()) {
291 ret += QString(escapeChar());
292 return 2;
293 }
294 int sl;
295 int rsl;
296 int rpos;
297 if (str.unicode()[pos + 1].unicode() == '{') {
298 rpos = pos + 2;
299 if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) {
300 return 0;
301 }
302 sl -= rpos;
303 rsl = sl + 3;
304 } else {
305 rpos = pos + 1;
306 for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl) {
307 ;
308 }
309 rsl = sl + 1;
310 }
311 if (!sl) {
312 return 0;
313 }
314 if (expandMacro(str.mid(rpos, sl), ret)) {
315 return rsl;
316 }
317 return 0;
318}
319
320////////////
321
322template<typename KT, typename VT>
323inline QString TexpandMacros(const QString &ostr, const QHash<KT, VT> &map, QChar c)
324{
325 QString str(ostr);
326 KMacroMapExpander<KT, VT> kmx(map, c);
327 kmx.expandMacros(str);
328 return str;
329}
330
331template<typename KT, typename VT>
332inline QString TexpandMacrosShellQuote(const QString &ostr, const QHash<KT, VT> &map, QChar c)
333{
334 QString str(ostr);
335 KMacroMapExpander<KT, VT> kmx(map, c);
336 if (!kmx.expandMacrosShellQuote(str)) {
337 return QString();
338 }
339 return str;
340}
341
342// public API
344{
346{
347 return TexpandMacros(ostr, map, c);
348}
350{
351 return TexpandMacrosShellQuote(ostr, map, c);
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}
377
378} // namespace
int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override
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
Abstract base class for the worker classes behind the KMacroExpander namespace and the KCharMacroExpa...
void expandMacros(QString &str)
Perform safe macro expansion (substitution) on a string.
QChar escapeChar() const
Obtain the macro escape character.
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.
void setEscapeChar(QChar c)
Set the macro escape character.
virtual ~KMacroExpanderBase()
Destructor.
KMacroExpanderBase(QChar c=QLatin1Char('%'))
Constructor.
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.
bool expandMacrosShellQuote(QString &str, int &pos)
Perform safe macro expansion (substitution) on a string for use in shell commands.
int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override
int expandPlainMacro(const QString &str, int pos, QStringList &ret) override
virtual bool expandMacro(const QString &str, QStringList &ret)=0
Return substitution list ret for string macro str.
KDB_EXPORT bool isIdentifier(const QString &s)
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.
char16_t & unicode()
void clear()
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
const QChar * unicode() const const
QString join(QChar separator) const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:31 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.