fix logic
[personal-kdelibs.git] / kdecore / util / kmacroexpander.cpp
blob783e0596707ff2d1eb892370aa0c5eb78539aeef
1 /*
2 This file is part of the KDE libraries
4 Copyright (c) 2002-2003 Oswald Buddenhagen <ossi@kde.org>
5 Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
23 #include "kmacroexpander_p.h"
24 #include "kdebug.h"
26 #include <QtCore/QHash>
27 #include <QtCore/QStringList>
29 KMacroExpanderBase::KMacroExpanderBase( QChar c ) : d(new KMacroExpanderBasePrivate(c))
33 KMacroExpanderBase::~KMacroExpanderBase()
35 delete d;
38 void
39 KMacroExpanderBase::setEscapeChar( QChar c )
41 d->escapechar = c;
44 QChar
45 KMacroExpanderBase::escapeChar() const
47 return d->escapechar;
50 void KMacroExpanderBase::expandMacros( QString &str )
52 int pos;
53 int len;
54 QChar ec( d->escapechar );
55 QStringList rst;
56 QString rsts;
58 for (pos = 0; pos < str.length(); ) {
59 if (ec != QLatin1Char(0) ) {
60 if (str.unicode()[pos] != ec)
61 goto nohit;
62 if (!(len = expandEscapedMacro( str, pos, rst )))
63 goto nohit;
64 } else {
65 if (!(len = expandPlainMacro( str, pos, rst )))
66 goto nohit;
68 if (len < 0) {
69 pos -= len;
70 continue;
72 rsts = rst.join( QLatin1String(" ") );
73 rst.clear();
74 str.replace( pos, len, rsts );
75 pos += rsts.length();
76 continue;
77 nohit:
78 pos++;
82 bool KMacroExpanderBase::expandMacrosShellQuote( QString &str )
84 int pos = 0;
85 return expandMacrosShellQuote( str, pos ) && pos == str.length();
88 int KMacroExpanderBase::expandPlainMacro( const QString &, int, QStringList & )
89 { qFatal( "KMacroExpanderBase::expandPlainMacro called!" ); return 0; }
91 int KMacroExpanderBase::expandEscapedMacro( const QString &, int, QStringList & )
92 { qFatal( "KMacroExpanderBase::expandEscapedMacro called!" ); return 0; }
95 //////////////////////////////////////////////////
97 template <typename KT, typename VT>
98 class KMacroMapExpander : public KMacroExpanderBase {
100 public:
101 KMacroMapExpander( const QHash<KT,VT> &map, QChar c = QLatin1Char('%') ) :
102 KMacroExpanderBase( c ), macromap( map ) {}
104 protected:
105 virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret );
106 virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
108 private:
109 QHash<KT,VT> macromap;
112 static QStringList &operator+=( QStringList &s, const QString &n) { s << n; return s; }
114 ////////
116 static bool
117 isIdentifier( QChar c )
119 return c == QLatin1Char('_') ||
120 (c >= QLatin1Char('A') && c <= QLatin1Char('Z')) ||
121 (c >= QLatin1Char('a') && c <= QLatin1Char('z')) ||
122 (c >= QLatin1Char('0') && c <= QLatin1Char('9'));
125 ////////
127 template <typename VT>
128 class KMacroMapExpander<QChar,VT> : public KMacroExpanderBase {
130 public:
131 KMacroMapExpander( const QHash<QChar,VT> &map, QChar c = QLatin1Char('%') ) :
132 KMacroExpanderBase( c ), macromap( map ) {}
134 protected:
135 virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret );
136 virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
138 private:
139 QHash<QChar,VT> macromap;
142 template <typename VT>
144 KMacroMapExpander<QChar,VT>::expandPlainMacro( const QString &str, int pos, QStringList &ret )
146 typename QHash<QChar,VT>::const_iterator it = macromap.constFind(str[pos]);
147 if (it != macromap.constEnd()) {
148 ret += it.value();
149 return 1;
151 return 0;
154 template <typename VT>
156 KMacroMapExpander<QChar,VT>::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
158 if (str[pos + 1] == escapeChar()) {
159 ret += QString( escapeChar() );
160 return 2;
162 typename QHash<QChar,VT>::const_iterator it = macromap.constFind(str[pos+1]);
163 if (it != macromap.constEnd()) {
164 ret += it.value();
165 return 2;
168 return 0;
171 template <typename VT>
172 class KMacroMapExpander<QString,VT> : public KMacroExpanderBase {
174 public:
175 KMacroMapExpander( const QHash<QString,VT> &map, QChar c = QLatin1Char('%') ) :
176 KMacroExpanderBase( c ), macromap( map ) {}
178 protected:
179 virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret );
180 virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
182 private:
183 QHash<QString,VT> macromap;
186 template <typename VT>
188 KMacroMapExpander<QString,VT>::expandPlainMacro( const QString &str, int pos, QStringList &ret )
190 if (isIdentifier( str[pos - 1] ))
191 return 0;
192 int sl;
193 for (sl = 0; isIdentifier( str[pos + sl] ); sl++)
195 if (!sl)
196 return 0;
197 typename QHash<QString,VT>::const_iterator it =
198 macromap.constFind( str.mid( pos, sl ) );
199 if (it != macromap.constEnd()) {
200 ret += it.value();
201 return sl;
203 return 0;
206 template <typename VT>
208 KMacroMapExpander<QString,VT>::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
210 if (str.length() <= pos + 1)
211 return 0;
213 if (str[pos + 1] == escapeChar()) {
214 ret += QString( escapeChar() );
215 return 2;
217 int sl, rsl, rpos;
218 if (str[pos + 1] == QLatin1Char('{')) {
219 rpos = pos + 2;
220 sl = str.indexOf(QLatin1Char('}'), rpos);
221 if (sl == -1)
222 return 0;
223 else
224 sl -= rpos;
225 rsl = sl + 3;
226 } else {
227 rpos = pos + 1;
228 for (sl = 0; (rpos + sl < str.length()) && isIdentifier( str[rpos + sl] ); sl++)
230 rsl = sl + 1;
232 if (!sl)
233 return 0;
234 typename QHash<QString,VT>::const_iterator it =
235 macromap.constFind( str.mid( rpos, sl ) );
236 if (it != macromap.constEnd()) {
237 ret += it.value();
238 return rsl;
240 return 0;
243 ////////////
246 KCharMacroExpander::expandPlainMacro( const QString &str, int pos, QStringList &ret )
248 if (expandMacro( str[pos], ret ))
249 return 1;
250 return 0;
254 KCharMacroExpander::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
256 if (str[pos + 1] == escapeChar()) {
257 ret += QString( escapeChar() );
258 return 2;
260 if (expandMacro( str[pos+1], ret ))
261 return 2;
262 return 0;
266 KWordMacroExpander::expandPlainMacro( const QString &str, int pos, QStringList &ret )
268 if (isIdentifier( str[pos - 1] ))
269 return 0;
270 int sl;
271 for (sl = 0; isIdentifier( str[pos + sl] ); sl++)
273 if (!sl)
274 return 0;
275 if (expandMacro( str.mid( pos, sl ), ret ))
276 return sl;
277 return 0;
281 KWordMacroExpander::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
283 if (str[pos + 1] == escapeChar()) {
284 ret += QString( escapeChar() );
285 return 2;
287 int sl, rsl, rpos;
288 if (str[pos + 1] == QLatin1Char('{')) {
289 rpos = pos + 2;
290 for (sl = 0; str[rpos + sl] != QLatin1Char('}'); sl++)
291 if (rpos + sl >= str.length())
292 return 0;
293 rsl = sl + 3;
294 } else {
295 rpos = pos + 1;
296 for (sl = 0; isIdentifier( str[rpos + sl] ); sl++)
298 rsl = sl + 1;
300 if (!sl)
301 return 0;
302 if (expandMacro( str.mid( rpos, sl ), ret ))
303 return rsl;
304 return 0;
307 ////////////
309 template <typename KT, typename VT>
310 inline QString
311 TexpandMacros( const QString &ostr, const QHash<KT,VT> &map, QChar c )
313 QString str( ostr );
314 KMacroMapExpander<KT,VT> kmx( map, c );
315 kmx.expandMacros( str );
316 return str;
319 template <typename KT, typename VT>
320 inline QString
321 TexpandMacrosShellQuote( const QString &ostr, const QHash<KT,VT> &map, QChar c )
323 QString str( ostr );
324 KMacroMapExpander<KT,VT> kmx( map, c );
325 if (!kmx.expandMacrosShellQuote( str ))
326 return QString();
327 return str;
330 // public API
331 namespace KMacroExpander {
333 QString expandMacros( const QString &ostr, const QHash<QChar,QString> &map, QChar c )
334 { return TexpandMacros( ostr, map, c ); }
335 QString expandMacrosShellQuote( const QString &ostr, const QHash<QChar,QString> &map, QChar c )
336 { return TexpandMacrosShellQuote( ostr, map, c ); }
337 QString expandMacros( const QString &ostr, const QHash<QString,QString> &map, QChar c )
338 { return TexpandMacros( ostr, map, c ); }
339 QString expandMacrosShellQuote( const QString &ostr, const QHash<QString,QString> &map, QChar c )
340 { return TexpandMacrosShellQuote( ostr, map, c ); }
341 QString expandMacros( const QString &ostr, const QHash<QChar,QStringList> &map, QChar c )
342 { return TexpandMacros( ostr, map, c ); }
343 QString expandMacrosShellQuote( const QString &ostr, const QHash<QChar,QStringList> &map, QChar c )
344 { return TexpandMacrosShellQuote( ostr, map, c ); }
345 QString expandMacros( const QString &ostr, const QHash<QString,QStringList> &map, QChar c )
346 { return TexpandMacros( ostr, map, c ); }
347 QString expandMacrosShellQuote( const QString &ostr, const QHash<QString,QStringList> &map, QChar c )
348 { return TexpandMacrosShellQuote( ostr, map, c ); }
350 } // namespace