/* 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[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 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[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[pos + 1] == escapeChar()) { ret += QString( escapeChar() ); return 2; } typename QHash::const_iterator it = macromap.constFind(str[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[pos - 1].unicode())) { return 0; } int sl = 0; for (sl = 0; isIdentifier(str[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[pos + 1] == escapeChar()) { ret += QString(escapeChar()); return 2; } int sl = 0; int rsl = 0; int rpos = 0; if (str[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[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[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[pos + 1] == escapeChar()) { ret += QString(escapeChar()); return 2; } if (expandMacro(str[pos + 1], ret)) { return 2; } return 0; } int KWordMacroExpander::expandPlainMacro(const QString &str, int pos, QStringList &ret) { if (pos && isIdentifier(str[pos - 1].unicode())) { return 0; } int sl = 0; for (sl = 0; isIdentifier(str[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[pos + 1] == escapeChar()) { ret += QString(escapeChar()); return 2; } int sl = 0; int rsl = 0; int rpos = 0; if (str[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[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