File indexing completed on 2024-04-28 03:53:48
0001 /* 0002 This file is part of the KDE libraries 0003 0004 SPDX-FileCopyrightText: 2002-2003 Oswald Buddenhagen <ossi@kde.org> 0005 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "kmacroexpander_p.h" 0011 0012 #include <QHash> 0013 0014 KMacroExpanderBase::KMacroExpanderBase(QChar c) 0015 : d(new KMacroExpanderBasePrivate(c)) 0016 { 0017 } 0018 0019 KMacroExpanderBase::~KMacroExpanderBase() = default; 0020 0021 void KMacroExpanderBase::setEscapeChar(QChar c) 0022 { 0023 d->escapechar = c; 0024 } 0025 0026 QChar KMacroExpanderBase::escapeChar() const 0027 { 0028 return d->escapechar; 0029 } 0030 0031 void KMacroExpanderBase::expandMacros(QString &str) 0032 { 0033 int pos; 0034 int len; 0035 ushort ec = d->escapechar.unicode(); 0036 QStringList rst; 0037 QString rsts; 0038 0039 for (pos = 0; pos < str.length();) { 0040 if (ec != 0) { 0041 if (str.unicode()[pos].unicode() != ec) { 0042 goto nohit; 0043 } 0044 if (!(len = expandEscapedMacro(str, pos, rst))) { 0045 goto nohit; 0046 } 0047 } else { 0048 if (!(len = expandPlainMacro(str, pos, rst))) { 0049 goto nohit; 0050 } 0051 } 0052 if (len < 0) { 0053 pos -= len; 0054 continue; 0055 } 0056 rsts = rst.join(QLatin1Char(' ')); 0057 rst.clear(); 0058 str.replace(pos, len, rsts); 0059 pos += rsts.length(); 0060 continue; 0061 nohit: 0062 pos++; 0063 } 0064 } 0065 0066 bool KMacroExpanderBase::expandMacrosShellQuote(QString &str) 0067 { 0068 int pos = 0; 0069 return expandMacrosShellQuote(str, pos) && pos == str.length(); 0070 } 0071 0072 int KMacroExpanderBase::expandPlainMacro(const QString &, int, QStringList &) 0073 { 0074 qFatal("KMacroExpanderBase::expandPlainMacro called!"); 0075 return 0; 0076 } 0077 0078 int KMacroExpanderBase::expandEscapedMacro(const QString &, int, QStringList &) 0079 { 0080 qFatal("KMacroExpanderBase::expandEscapedMacro called!"); 0081 return 0; 0082 } 0083 0084 ////////////////////////////////////////////////// 0085 0086 template<typename KT, typename VT> 0087 class KMacroMapExpander : public KMacroExpanderBase 0088 { 0089 public: 0090 KMacroMapExpander(const QHash<KT, VT> &map, QChar c = QLatin1Char('%')) 0091 : KMacroExpanderBase(c) 0092 , macromap(map) 0093 { 0094 } 0095 0096 protected: 0097 int expandPlainMacro(const QString &str, int pos, QStringList &ret) override; 0098 int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override; 0099 0100 private: 0101 QHash<KT, VT> macromap; 0102 }; 0103 0104 //////// 0105 0106 static bool isIdentifier(ushort c) 0107 { 0108 return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); 0109 } 0110 0111 //////// 0112 0113 template<typename VT> 0114 class KMacroMapExpander<QChar, VT> : public KMacroExpanderBase 0115 { 0116 public: 0117 KMacroMapExpander(const QHash<QChar, VT> &map, QChar c = QLatin1Char('%')) 0118 : KMacroExpanderBase(c) 0119 , macromap(map) 0120 { 0121 } 0122 0123 protected: 0124 int expandPlainMacro(const QString &str, int pos, QStringList &ret) override; 0125 int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override; 0126 0127 private: 0128 QHash<QChar, VT> macromap; 0129 }; 0130 0131 template<typename VT> 0132 int KMacroMapExpander<QChar, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret) 0133 { 0134 typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos]); 0135 if (it != macromap.constEnd()) { 0136 ret += it.value(); 0137 return 1; 0138 } 0139 return 0; 0140 } 0141 0142 template<typename VT> 0143 int KMacroMapExpander<QChar, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret) 0144 { 0145 if (str.length() <= pos + 1) { 0146 return 0; 0147 } 0148 0149 if (str.unicode()[pos + 1] == escapeChar()) { 0150 ret += QString(escapeChar()); 0151 return 2; 0152 } 0153 typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos + 1]); 0154 if (it != macromap.constEnd()) { 0155 ret += it.value(); 0156 return 2; 0157 } 0158 0159 return 0; 0160 } 0161 0162 template<typename VT> 0163 class KMacroMapExpander<QString, VT> : public KMacroExpanderBase 0164 { 0165 public: 0166 KMacroMapExpander(const QHash<QString, VT> &map, QChar c = QLatin1Char('%')) 0167 : KMacroExpanderBase(c) 0168 , macromap(map) 0169 { 0170 } 0171 0172 protected: 0173 int expandPlainMacro(const QString &str, int pos, QStringList &ret) override; 0174 int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override; 0175 0176 private: 0177 QHash<QString, VT> macromap; 0178 }; 0179 0180 template<typename VT> 0181 int KMacroMapExpander<QString, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret) 0182 { 0183 if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) { 0184 return 0; 0185 } 0186 int sl; 0187 for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++) { 0188 ; 0189 } 0190 if (!sl) { 0191 return 0; 0192 } 0193 typename QHash<QString, VT>::const_iterator it = macromap.constFind(str.mid(pos, sl)); 0194 if (it != macromap.constEnd()) { 0195 ret += it.value(); 0196 return sl; 0197 } 0198 return 0; 0199 } 0200 0201 template<typename VT> 0202 int KMacroMapExpander<QString, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret) 0203 { 0204 if (str.length() <= pos + 1) { 0205 return 0; 0206 } 0207 0208 if (str.unicode()[pos + 1] == escapeChar()) { 0209 ret += QString(escapeChar()); 0210 return 2; 0211 } 0212 int sl; 0213 int rsl; 0214 int rpos; 0215 if (str.unicode()[pos + 1].unicode() == '{') { 0216 rpos = pos + 2; 0217 if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) { 0218 return 0; 0219 } 0220 sl -= rpos; 0221 rsl = sl + 3; 0222 } else { 0223 rpos = pos + 1; 0224 for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl) { 0225 ; 0226 } 0227 rsl = sl + 1; 0228 } 0229 if (!sl) { 0230 return 0; 0231 } 0232 typename QHash<QString, VT>::const_iterator it = macromap.constFind(str.mid(rpos, sl)); 0233 if (it != macromap.constEnd()) { 0234 ret += it.value(); 0235 return rsl; 0236 } 0237 return 0; 0238 } 0239 0240 //////////// 0241 0242 int KCharMacroExpander::expandPlainMacro(const QString &str, int pos, QStringList &ret) 0243 { 0244 if (expandMacro(str.unicode()[pos], ret)) { 0245 return 1; 0246 } 0247 return 0; 0248 } 0249 0250 int KCharMacroExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret) 0251 { 0252 if (str.length() <= pos + 1) { 0253 return 0; 0254 } 0255 0256 if (str.unicode()[pos + 1] == escapeChar()) { 0257 ret += QString(escapeChar()); 0258 return 2; 0259 } 0260 if (expandMacro(str.unicode()[pos + 1], ret)) { 0261 return 2; 0262 } 0263 return 0; 0264 } 0265 0266 int KWordMacroExpander::expandPlainMacro(const QString &str, int pos, QStringList &ret) 0267 { 0268 if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) { 0269 return 0; 0270 } 0271 int sl; 0272 for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++) { 0273 ; 0274 } 0275 if (!sl) { 0276 return 0; 0277 } 0278 if (expandMacro(str.mid(pos, sl), ret)) { 0279 return sl; 0280 } 0281 return 0; 0282 } 0283 0284 int KWordMacroExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret) 0285 { 0286 if (str.length() <= pos + 1) { 0287 return 0; 0288 } 0289 0290 if (str.unicode()[pos + 1] == escapeChar()) { 0291 ret += QString(escapeChar()); 0292 return 2; 0293 } 0294 int sl; 0295 int rsl; 0296 int rpos; 0297 if (str.unicode()[pos + 1].unicode() == '{') { 0298 rpos = pos + 2; 0299 if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) { 0300 return 0; 0301 } 0302 sl -= rpos; 0303 rsl = sl + 3; 0304 } else { 0305 rpos = pos + 1; 0306 for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl) { 0307 ; 0308 } 0309 rsl = sl + 1; 0310 } 0311 if (!sl) { 0312 return 0; 0313 } 0314 if (expandMacro(str.mid(rpos, sl), ret)) { 0315 return rsl; 0316 } 0317 return 0; 0318 } 0319 0320 //////////// 0321 0322 template<typename KT, typename VT> 0323 inline QString TexpandMacros(const QString &ostr, const QHash<KT, VT> &map, QChar c) 0324 { 0325 QString str(ostr); 0326 KMacroMapExpander<KT, VT> kmx(map, c); 0327 kmx.expandMacros(str); 0328 return str; 0329 } 0330 0331 template<typename KT, typename VT> 0332 inline QString TexpandMacrosShellQuote(const QString &ostr, const QHash<KT, VT> &map, QChar c) 0333 { 0334 QString str(ostr); 0335 KMacroMapExpander<KT, VT> kmx(map, c); 0336 if (!kmx.expandMacrosShellQuote(str)) { 0337 return QString(); 0338 } 0339 return str; 0340 } 0341 0342 // public API 0343 namespace KMacroExpander 0344 { 0345 QString expandMacros(const QString &ostr, const QHash<QChar, QString> &map, QChar c) 0346 { 0347 return TexpandMacros(ostr, map, c); 0348 } 0349 QString expandMacrosShellQuote(const QString &ostr, const QHash<QChar, QString> &map, QChar c) 0350 { 0351 return TexpandMacrosShellQuote(ostr, map, c); 0352 } 0353 QString expandMacros(const QString &ostr, const QHash<QString, QString> &map, QChar c) 0354 { 0355 return TexpandMacros(ostr, map, c); 0356 } 0357 QString expandMacrosShellQuote(const QString &ostr, const QHash<QString, QString> &map, QChar c) 0358 { 0359 return TexpandMacrosShellQuote(ostr, map, c); 0360 } 0361 QString expandMacros(const QString &ostr, const QHash<QChar, QStringList> &map, QChar c) 0362 { 0363 return TexpandMacros(ostr, map, c); 0364 } 0365 QString expandMacrosShellQuote(const QString &ostr, const QHash<QChar, QStringList> &map, QChar c) 0366 { 0367 return TexpandMacrosShellQuote(ostr, map, c); 0368 } 0369 QString expandMacros(const QString &ostr, const QHash<QString, QStringList> &map, QChar c) 0370 { 0371 return TexpandMacros(ostr, map, c); 0372 } 0373 QString expandMacrosShellQuote(const QString &ostr, const QHash<QString, QStringList> &map, QChar c) 0374 { 0375 return TexpandMacrosShellQuote(ostr, map, c); 0376 } 0377 0378 } // namespace