00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kmacroexpander_p.h"
00024 #include "kdebug.h"
00025
00026 #include <QtCore/QHash>
00027 #include <QtCore/QStringList>
00028
00029 KMacroExpanderBase::KMacroExpanderBase( QChar c ) : d(new KMacroExpanderBasePrivate(c))
00030 {
00031 }
00032
00033 KMacroExpanderBase::~KMacroExpanderBase()
00034 {
00035 delete d;
00036 }
00037
00038 void
00039 KMacroExpanderBase::setEscapeChar( QChar c )
00040 {
00041 d->escapechar = c;
00042 }
00043
00044 QChar
00045 KMacroExpanderBase::escapeChar() const
00046 {
00047 return d->escapechar;
00048 }
00049
00050 void KMacroExpanderBase::expandMacros( QString &str )
00051 {
00052 int pos;
00053 int len;
00054 ushort ec = d->escapechar.unicode();
00055 QStringList rst;
00056 QString rsts;
00057
00058 for (pos = 0; pos < str.length(); ) {
00059 if (ec != 0) {
00060 if (str.unicode()[pos].unicode() != ec)
00061 goto nohit;
00062 if (!(len = expandEscapedMacro( str, pos, rst )))
00063 goto nohit;
00064 } else {
00065 if (!(len = expandPlainMacro( str, pos, rst )))
00066 goto nohit;
00067 }
00068 if (len < 0) {
00069 pos -= len;
00070 continue;
00071 }
00072 rsts = rst.join( QLatin1String(" ") );
00073 rst.clear();
00074 str.replace( pos, len, rsts );
00075 pos += rsts.length();
00076 continue;
00077 nohit:
00078 pos++;
00079 }
00080 }
00081
00082 bool KMacroExpanderBase::expandMacrosShellQuote( QString &str )
00083 {
00084 int pos = 0;
00085 return expandMacrosShellQuote( str, pos ) && pos == str.length();
00086 }
00087
00088 int KMacroExpanderBase::expandPlainMacro( const QString &, int, QStringList & )
00089 { qFatal( "KMacroExpanderBase::expandPlainMacro called!" ); return 0; }
00090
00091 int KMacroExpanderBase::expandEscapedMacro( const QString &, int, QStringList & )
00092 { qFatal( "KMacroExpanderBase::expandEscapedMacro called!" ); return 0; }
00093
00094
00096
00097 template <typename KT, typename VT>
00098 class KMacroMapExpander : public KMacroExpanderBase {
00099
00100 public:
00101 KMacroMapExpander( const QHash<KT,VT> &map, QChar c = QLatin1Char('%') ) :
00102 KMacroExpanderBase( c ), macromap( map ) {}
00103
00104 protected:
00105 virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret );
00106 virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
00107
00108 private:
00109 QHash<KT,VT> macromap;
00110 };
00111
00112 static QStringList &operator+=( QStringList &s, const QString &n) { s << n; return s; }
00113
00115
00116 static bool
00117 isIdentifier( ushort c )
00118 {
00119 return c == '_' ||
00120 (c >= 'A' && c <= 'Z') ||
00121 (c >= 'a' && c <= 'z') ||
00122 (c >= '0' && c <= '9');
00123 }
00124
00126
00127 template <typename VT>
00128 class KMacroMapExpander<QChar,VT> : public KMacroExpanderBase {
00129
00130 public:
00131 KMacroMapExpander( const QHash<QChar,VT> &map, QChar c = QLatin1Char('%') ) :
00132 KMacroExpanderBase( c ), macromap( map ) {}
00133
00134 protected:
00135 virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret );
00136 virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
00137
00138 private:
00139 QHash<QChar,VT> macromap;
00140 };
00141
00142 template <typename VT>
00143 int
00144 KMacroMapExpander<QChar,VT>::expandPlainMacro( const QString &str, int pos, QStringList &ret )
00145 {
00146 typename QHash<QChar,VT>::const_iterator it = macromap.constFind(str.unicode()[pos]);
00147 if (it != macromap.constEnd()) {
00148 ret += it.value();
00149 return 1;
00150 }
00151 return 0;
00152 }
00153
00154 template <typename VT>
00155 int
00156 KMacroMapExpander<QChar,VT>::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
00157 {
00158 if (str.length() <= pos + 1)
00159 return 0;
00160
00161 if (str.unicode()[pos + 1] == escapeChar()) {
00162 ret += QString( escapeChar() );
00163 return 2;
00164 }
00165 typename QHash<QChar,VT>::const_iterator it = macromap.constFind(str.unicode()[pos + 1]);
00166 if (it != macromap.constEnd()) {
00167 ret += it.value();
00168 return 2;
00169 }
00170
00171 return 0;
00172 }
00173
00174 template <typename VT>
00175 class KMacroMapExpander<QString,VT> : public KMacroExpanderBase {
00176
00177 public:
00178 KMacroMapExpander( const QHash<QString,VT> &map, QChar c = QLatin1Char('%') ) :
00179 KMacroExpanderBase( c ), macromap( map ) {}
00180
00181 protected:
00182 virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret );
00183 virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
00184
00185 private:
00186 QHash<QString,VT> macromap;
00187 };
00188
00189 template <typename VT>
00190 int
00191 KMacroMapExpander<QString,VT>::expandPlainMacro( const QString &str, int pos, QStringList &ret )
00192 {
00193 if (pos && isIdentifier( str.unicode()[pos - 1].unicode() ))
00194 return 0;
00195 int sl;
00196 for (sl = 0; isIdentifier( str.unicode()[pos + sl].unicode() ); sl++)
00197 ;
00198 if (!sl)
00199 return 0;
00200 typename QHash<QString,VT>::const_iterator it =
00201 macromap.constFind( str.mid( pos, sl ) );
00202 if (it != macromap.constEnd()) {
00203 ret += it.value();
00204 return sl;
00205 }
00206 return 0;
00207 }
00208
00209 template <typename VT>
00210 int
00211 KMacroMapExpander<QString,VT>::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
00212 {
00213 if (str.length() <= pos + 1)
00214 return 0;
00215
00216 if (str.unicode()[pos + 1] == escapeChar()) {
00217 ret += QString( escapeChar() );
00218 return 2;
00219 }
00220 int sl, rsl, rpos;
00221 if (str.unicode()[pos + 1].unicode() == '{') {
00222 rpos = pos + 2;
00223 if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0)
00224 return 0;
00225 sl -= rpos;
00226 rsl = sl + 3;
00227 } else {
00228 rpos = pos + 1;
00229 for (sl = 0; isIdentifier( str.unicode()[rpos + sl].unicode() ); sl++)
00230 ;
00231 rsl = sl + 1;
00232 }
00233 if (!sl)
00234 return 0;
00235 typename QHash<QString,VT>::const_iterator it =
00236 macromap.constFind( str.mid( rpos, sl ) );
00237 if (it != macromap.constEnd()) {
00238 ret += it.value();
00239 return rsl;
00240 }
00241 return 0;
00242 }
00243
00245
00246 int
00247 KCharMacroExpander::expandPlainMacro( const QString &str, int pos, QStringList &ret )
00248 {
00249 if (expandMacro( str.unicode()[pos], ret ))
00250 return 1;
00251 return 0;
00252 }
00253
00254 int
00255 KCharMacroExpander::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
00256 {
00257 if (str.length() <= pos + 1)
00258 return 0;
00259
00260 if (str.unicode()[pos + 1] == escapeChar()) {
00261 ret += QString( escapeChar() );
00262 return 2;
00263 }
00264 if (expandMacro( str.unicode()[pos + 1], ret ))
00265 return 2;
00266 return 0;
00267 }
00268
00269 int
00270 KWordMacroExpander::expandPlainMacro( const QString &str, int pos, QStringList &ret )
00271 {
00272 if (pos && isIdentifier( str.unicode()[pos - 1].unicode() ))
00273 return 0;
00274 int sl;
00275 for (sl = 0; isIdentifier( str.unicode()[pos + sl].unicode() ); sl++)
00276 ;
00277 if (!sl)
00278 return 0;
00279 if (expandMacro( str.mid( pos, sl ), ret ))
00280 return sl;
00281 return 0;
00282 }
00283
00284 int
00285 KWordMacroExpander::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
00286 {
00287 if (str.length() <= pos + 1)
00288 return 0;
00289
00290 if (str.unicode()[pos + 1] == escapeChar()) {
00291 ret += QString( escapeChar() );
00292 return 2;
00293 }
00294 int sl, rsl, rpos;
00295 if (str.unicode()[pos + 1].unicode() == '{') {
00296 rpos = pos + 2;
00297 if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0)
00298 return 0;
00299 sl -= rpos;
00300 rsl = sl + 3;
00301 } else {
00302 rpos = pos + 1;
00303 for (sl = 0; isIdentifier( str.unicode()[rpos + sl].unicode() ); sl++)
00304 ;
00305 rsl = sl + 1;
00306 }
00307 if (!sl)
00308 return 0;
00309 if (expandMacro( str.mid( rpos, sl ), ret ))
00310 return rsl;
00311 return 0;
00312 }
00313
00315
00316 template <typename KT, typename VT>
00317 inline QString
00318 TexpandMacros( const QString &ostr, const QHash<KT,VT> &map, QChar c )
00319 {
00320 QString str( ostr );
00321 KMacroMapExpander<KT,VT> kmx( map, c );
00322 kmx.expandMacros( str );
00323 return str;
00324 }
00325
00326 template <typename KT, typename VT>
00327 inline QString
00328 TexpandMacrosShellQuote( const QString &ostr, const QHash<KT,VT> &map, QChar c )
00329 {
00330 QString str( ostr );
00331 KMacroMapExpander<KT,VT> kmx( map, c );
00332 if (!kmx.expandMacrosShellQuote( str ))
00333 return QString();
00334 return str;
00335 }
00336
00337
00338 namespace KMacroExpander {
00339
00340 QString expandMacros( const QString &ostr, const QHash<QChar,QString> &map, QChar c )
00341 { return TexpandMacros( ostr, map, c ); }
00342 QString expandMacrosShellQuote( const QString &ostr, const QHash<QChar,QString> &map, QChar c )
00343 { return TexpandMacrosShellQuote( ostr, map, c ); }
00344 QString expandMacros( const QString &ostr, const QHash<QString,QString> &map, QChar c )
00345 { return TexpandMacros( ostr, map, c ); }
00346 QString expandMacrosShellQuote( const QString &ostr, const QHash<QString,QString> &map, QChar c )
00347 { return TexpandMacrosShellQuote( ostr, map, c ); }
00348 QString expandMacros( const QString &ostr, const QHash<QChar,QStringList> &map, QChar c )
00349 { return TexpandMacros( ostr, map, c ); }
00350 QString expandMacrosShellQuote( const QString &ostr, const QHash<QChar,QStringList> &map, QChar c )
00351 { return TexpandMacrosShellQuote( ostr, map, c ); }
00352 QString expandMacros( const QString &ostr, const QHash<QString,QStringList> &map, QChar c )
00353 { return TexpandMacros( ostr, map, c ); }
00354 QString expandMacrosShellQuote( const QString &ostr, const QHash<QString,QStringList> &map, QChar c )
00355 { return TexpandMacrosShellQuote( ostr, map, c ); }
00356
00357 }