/* This file is part of the KDE libraries Copyright (c) 2002-2003 Oswald Buddenhagen Copyright (c) 2003 Waldo Bastian This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kmacroexpander_p.h" #include "kdebug.h" #include #include KMacroExpanderBase::KMacroExpanderBase( QChar c ) : d(new KMacroExpanderBasePrivate(c)) { } KMacroExpanderBase::~KMacroExpanderBase() { delete d; } void KMacroExpanderBase::setEscapeChar( QChar c ) { d->escapechar = c; } QChar KMacroExpanderBase::escapeChar() const { return d->escapechar; } void KMacroExpanderBase::expandMacros( QString &str ) { int pos; int len; ushort ec = d->escapechar.unicode(); QStringList rst; QString rsts; for (pos = 0; pos < str.length(); ) { if (ec != 0) { if (str.unicode()[pos].unicode() != ec) goto nohit; if (!(len = expandEscapedMacro( str, pos, rst ))) goto nohit; } else { if (!(len = expandPlainMacro( str, pos, rst ))) goto nohit; } if (len < 0) { pos -= len; continue; } rsts = rst.join( QLatin1String(" ") ); rst.clear(); str.replace( pos, len, rsts ); pos += rsts.length(); continue; nohit: pos++; } } bool KMacroExpanderBase::expandMacrosShellQuote( QString &str ) { int pos = 0; return expandMacrosShellQuote( str, pos ) && pos == str.length(); } int KMacroExpanderBase::expandPlainMacro( const QString &, int, QStringList & ) { qFatal( "KMacroExpanderBase::expandPlainMacro called!" ); return 0; } int KMacroExpanderBase::expandEscapedMacro( const QString &, int, QStringList & ) { qFatal( "KMacroExpanderBase::expandEscapedMacro called!" ); return 0; } ////////////////////////////////////////////////// template class KMacroMapExpander : public KMacroExpanderBase { public: KMacroMapExpander( const QHash &map, QChar c = QLatin1Char('%') ) : KMacroExpanderBase( c ), macromap( map ) {} protected: virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret ); virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret ); private: QHash macromap; }; static QStringList &operator+=( QStringList &s, const QString &n) { s << n; return s; } //////// static bool isIdentifier( ushort c ) { return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); } //////// template class KMacroMapExpander : public KMacroExpanderBase { public: KMacroMapExpander( const QHash &map, QChar c = QLatin1Char('%') ) : KMacroExpanderBase( c ), macromap( map ) {} protected: virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret ); virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret ); private: QHash macromap; }; template int KMacroMapExpander::expandPlainMacro( const QString &str, int pos, QStringList &ret ) { typename QHash::const_iterator it = macromap.constFind(str.unicode()[pos]); if (it != macromap.constEnd()) { ret += it.value(); return 1; } return 0; } template int KMacroMapExpander::expandEscapedMacro( const QString &str, int pos, QStringList &ret ) { if (str.length() <= pos + 1) return 0; if (str.unicode()[pos + 1] == escapeChar()) { ret += QString( escapeChar() ); return 2; } typename QHash::const_iterator it = macromap.constFind(str.unicode()[pos + 1]); if (it != macromap.constEnd()) { ret += it.value(); return 2; } return 0; } template class KMacroMapExpander : public KMacroExpanderBase { public: KMacroMapExpander( const QHash &map, QChar c = QLatin1Char('%') ) : KMacroExpanderBase( c ), macromap( map ) {} protected: virtual int expandPlainMacro( const QString &str, int pos, QStringList &ret ); virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret ); private: QHash macromap; }; template int KMacroMapExpander::expandPlainMacro( const QString &str, int pos, QStringList &ret ) { if (pos && isIdentifier( str.unicode()[pos - 1].unicode() )) return 0; int sl; for (sl = 0; isIdentifier( str.unicode()[pos + sl].unicode() ); sl++) ; if (!sl) return 0; typename QHash::const_iterator it = macromap.constFind( str.mid( pos, sl ) ); if (it != macromap.constEnd()) { ret += it.value(); return sl; } return 0; } template int KMacroMapExpander::expandEscapedMacro( const QString &str, int pos, QStringList &ret ) { if (str.length() <= pos + 1) return 0; if (str.unicode()[pos + 1] == escapeChar()) { ret += QString( escapeChar() ); return 2; } int sl, rsl, rpos; if (str.unicode()[pos + 1].unicode() == '{') { rpos = pos + 2; if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) return 0; sl -= rpos; rsl = sl + 3; } else { rpos = pos + 1; for (sl = 0; isIdentifier( str.unicode()[rpos + sl].unicode() ); ++sl) ; rsl = sl + 1; } if (!sl) return 0; typename QHash::const_iterator it = macromap.constFind( str.mid( rpos, sl ) ); if (it != macromap.constEnd()) { ret += it.value(); return rsl; } return 0; } //////////// int KCharMacroExpander::expandPlainMacro( const QString &str, int pos, QStringList &ret ) { if (expandMacro( str.unicode()[pos], ret )) return 1; return 0; } int KCharMacroExpander::expandEscapedMacro( const QString &str, int pos, QStringList &ret ) { if (str.length() <= pos + 1) return 0; if (str.unicode()[pos + 1] == escapeChar()) { ret += QString( escapeChar() ); return 2; } if (expandMacro( str.unicode()[pos + 1], ret )) return 2; return 0; } int KWordMacroExpander::expandPlainMacro( const QString &str, int pos, QStringList &ret ) { if (pos && isIdentifier( str.unicode()[pos - 1].unicode() )) return 0; int sl; for (sl = 0; isIdentifier( str.unicode()[pos + sl].unicode() ); sl++) ; if (!sl) return 0; if (expandMacro( str.mid( pos, sl ), ret )) return sl; return 0; } int KWordMacroExpander::expandEscapedMacro( const QString &str, int pos, QStringList &ret ) { if (str.length() <= pos + 1) return 0; if (str.unicode()[pos + 1] == escapeChar()) { ret += QString( escapeChar() ); return 2; } int sl, rsl, rpos; if (str.unicode()[pos + 1].unicode() == '{') { rpos = pos + 2; if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) return 0; sl -= rpos; rsl = sl + 3; } else { rpos = pos + 1; for (sl = 0; isIdentifier( str.unicode()[rpos + sl].unicode() ); ++sl) ; rsl = sl + 1; } if (!sl) return 0; if (expandMacro( str.mid( rpos, sl ), ret )) return rsl; return 0; } //////////// template inline QString TexpandMacros( const QString &ostr, const QHash &map, QChar c ) { QString str( ostr ); KMacroMapExpander kmx( map, c ); kmx.expandMacros( str ); return str; } template inline QString TexpandMacrosShellQuote( const QString &ostr, const QHash &map, QChar c ) { QString str( ostr ); KMacroMapExpander kmx( map, c ); if (!kmx.expandMacrosShellQuote( str )) return QString(); return str; } // public API namespace KMacroExpander { QString expandMacros( const QString &ostr, const QHash &map, QChar c ) { return TexpandMacros( ostr, map, c ); } QString expandMacrosShellQuote( const QString &ostr, const QHash &map, QChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); } QString expandMacros( const QString &ostr, const QHash &map, QChar c ) { return TexpandMacros( ostr, map, c ); } QString expandMacrosShellQuote( const QString &ostr, const QHash &map, QChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); } QString expandMacros( const QString &ostr, const QHash &map, QChar c ) { return TexpandMacros( ostr, map, c ); } QString expandMacrosShellQuote( const QString &ostr, const QHash &map, QChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); } QString expandMacros( const QString &ostr, const QHash &map, QChar c ) { return TexpandMacros( ostr, map, c ); } QString expandMacrosShellQuote( const QString &ostr, const QHash &map, QChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); } } // namespace