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 QChar ec( d->escapechar );
00055 QStringList rst;
00056 QString rsts;
00057
00058 for (pos = 0; pos < str.length(); ) {
00059 if (ec != QLatin1Char(0) ) {
00060 if (str.unicode()[pos] != 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( QChar c )
00118 {
00119 return c == QLatin1Char('_') ||
00120 (c >= QLatin1Char('A') && c <= QLatin1Char('Z')) ||
00121 (c >= QLatin1Char('a') && c <= QLatin1Char('z')) ||
00122 (c >= QLatin1Char('0') && c <= QLatin1Char('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 const KMacroMapExpander<QChar,VT> *const_this = this;
00147 typename QHash<QChar,VT>::const_iterator it = const_this->macromap.find(str[pos]);
00148 if (it != const_this->macromap.end()) {
00149 ret += it.value();
00150 return 1;
00151 }
00152 return 0;
00153 }
00154
00155 template <typename VT>
00156 int
00157 KMacroMapExpander<QChar,VT>::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
00158 {
00159 if (str[pos + 1] == escapeChar()) {
00160 ret += QString( escapeChar() );
00161 return 2;
00162 }
00163 const KMacroMapExpander<QChar,VT> *const_this = this;
00164 typename QHash<QChar,VT>::const_iterator it = const_this->macromap.find(str[pos+1]);
00165 if (it != const_this->macromap.end()) {
00166 ret += it.value();
00167 return 2;
00168 }
00169
00170 return 0;
00171 }
00172
00173 template <typename VT>
00174 class KMacroMapExpander<QString,VT> : public KMacroExpanderBase {
00175
00176 public:
00177 KMacroMapExpander( const QHash<QString,VT> &map, QChar c = QLatin1Char('%') ) :
00178 KMacroExpanderBase( c ), macromap( map ) {}
00179
00180 protected:
00181 virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret );
00182 virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
00183
00184 private:
00185 QHash<QString,VT> macromap;
00186 };
00187
00188 template <typename VT>
00189 int
00190 KMacroMapExpander<QString,VT>::expandPlainMacro( const QString &str, int pos, QStringList &ret )
00191 {
00192 if (isIdentifier( str[pos - 1] ))
00193 return 0;
00194 int sl;
00195 for (sl = 0; isIdentifier( str[pos + sl] ); sl++)
00196 ;
00197 if (!sl)
00198 return 0;
00199 const KMacroMapExpander<QString,VT> *const_this = this;
00200 typename QHash<QString,VT>::const_iterator it =
00201 const_this->macromap.find( str.mid( pos, sl ) );
00202 if (it != const_this->macromap.end()) {
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[pos + 1] == escapeChar()) {
00217 ret += QString( escapeChar() );
00218 return 2;
00219 }
00220 int sl, rsl, rpos;
00221 if (str[pos + 1] == QLatin1Char('{')) {
00222 rpos = pos + 2;
00223 sl = str.indexOf(QLatin1Char('}'), rpos);
00224 if (sl == -1)
00225 return 0;
00226 else
00227 sl -= rpos;
00228 rsl = sl + 3;
00229 } else {
00230 rpos = pos + 1;
00231 for (sl = 0; (rpos + sl < str.length()) && isIdentifier( str[rpos + sl] ); sl++)
00232 ;
00233 rsl = sl + 1;
00234 }
00235 if (!sl)
00236 return 0;
00237 const KMacroMapExpander<QString,VT> *const_this = this;
00238 typename QHash<QString,VT>::const_iterator it =
00239 const_this->macromap.find( str.mid( rpos, sl ) );
00240 if (it != const_this->macromap.end()) {
00241 ret += it.value();
00242 return rsl;
00243 }
00244 return 0;
00245 }
00246
00248
00249 int
00250 KCharMacroExpander::expandPlainMacro( const QString &str, int pos, QStringList &ret )
00251 {
00252 if (expandMacro( str[pos], ret ))
00253 return 1;
00254 return 0;
00255 }
00256
00257 int
00258 KCharMacroExpander::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
00259 {
00260 if (str[pos + 1] == escapeChar()) {
00261 ret += QString( escapeChar() );
00262 return 2;
00263 }
00264 if (expandMacro( str[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 (isIdentifier( str[pos - 1] ))
00273 return 0;
00274 int sl;
00275 for (sl = 0; isIdentifier( str[pos + sl] ); 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[pos + 1] == escapeChar()) {
00288 ret += QString( escapeChar() );
00289 return 2;
00290 }
00291 int sl, rsl, rpos;
00292 if (str[pos + 1] == QLatin1Char('{')) {
00293 rpos = pos + 2;
00294 for (sl = 0; str[rpos + sl] != QLatin1Char('}'); sl++)
00295 if (rpos + sl >= str.length())
00296 return 0;
00297 rsl = sl + 3;
00298 } else {
00299 rpos = pos + 1;
00300 for (sl = 0; isIdentifier( str[rpos + sl] ); sl++)
00301 ;
00302 rsl = sl + 1;
00303 }
00304 if (!sl)
00305 return 0;
00306 if (expandMacro( str.mid( rpos, sl ), ret ))
00307 return rsl;
00308 return 0;
00309 }
00310
00312
00313 template <typename KT, typename VT>
00314 inline QString
00315 TexpandMacros( const QString &ostr, const QHash<KT,VT> &map, QChar c )
00316 {
00317 QString str( ostr );
00318 KMacroMapExpander<KT,VT> kmx( map, c );
00319 kmx.expandMacros( str );
00320 return str;
00321 }
00322
00323 template <typename KT, typename VT>
00324 inline QString
00325 TexpandMacrosShellQuote( const QString &ostr, const QHash<KT,VT> &map, QChar c )
00326 {
00327 QString str( ostr );
00328 KMacroMapExpander<KT,VT> kmx( map, c );
00329 if (!kmx.expandMacrosShellQuote( str ))
00330 return QString();
00331 return str;
00332 }
00333
00334
00335 namespace KMacroExpander {
00336
00337 QString expandMacros( const QString &ostr, const QHash<QChar,QString> &map, QChar c )
00338 { return TexpandMacros( ostr, map, c ); }
00339 QString expandMacrosShellQuote( const QString &ostr, const QHash<QChar,QString> &map, QChar c )
00340 { return TexpandMacrosShellQuote( ostr, map, c ); }
00341 QString expandMacros( const QString &ostr, const QHash<QString,QString> &map, QChar c )
00342 { return TexpandMacros( ostr, map, c ); }
00343 QString expandMacrosShellQuote( const QString &ostr, const QHash<QString,QString> &map, QChar c )
00344 { return TexpandMacrosShellQuote( ostr, map, c ); }
00345 QString expandMacros( const QString &ostr, const QHash<QChar,QStringList> &map, QChar c )
00346 { return TexpandMacros( ostr, map, c ); }
00347 QString expandMacrosShellQuote( const QString &ostr, const QHash<QChar,QStringList> &map, QChar c )
00348 { return TexpandMacrosShellQuote( ostr, map, c ); }
00349 QString expandMacros( const QString &ostr, const QHash<QString,QStringList> &map, QChar c )
00350 { return TexpandMacros( ostr, map, c ); }
00351 QString expandMacrosShellQuote( const QString &ostr, const QHash<QString,QStringList> &map, QChar c )
00352 { return TexpandMacrosShellQuote( ostr, map, c ); }
00353
00354 }