File indexing completed on 2024-05-12 15:34:58
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 static QStringList &operator+=(QStringList &s, const QString &n) 0105 { 0106 s << n; 0107 return s; 0108 } 0109 0110 //////// 0111 0112 static bool isIdentifier(ushort c) 0113 { 0114 return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); 0115 } 0116 0117 //////// 0118 0119 template<typename VT> 0120 class KMacroMapExpander<QChar, VT> : public KMacroExpanderBase 0121 { 0122 public: 0123 KMacroMapExpander(const QHash<QChar, VT> &map, QChar c = QLatin1Char('%')) 0124 : KMacroExpanderBase(c) 0125 , macromap(map) 0126 { 0127 } 0128 0129 protected: 0130 int expandPlainMacro(const QString &str, int pos, QStringList &ret) override; 0131 int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override; 0132 0133 private: 0134 QHash<QChar, VT> macromap; 0135 }; 0136 0137 template<typename VT> 0138 int KMacroMapExpander<QChar, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret) 0139 { 0140 typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos]); 0141 if (it != macromap.constEnd()) { 0142 ret += it.value(); 0143 return 1; 0144 } 0145 return 0; 0146 } 0147 0148 template<typename VT> 0149 int KMacroMapExpander<QChar, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret) 0150 { 0151 if (str.length() <= pos + 1) { 0152 return 0; 0153 } 0154 0155 if (str.unicode()[pos + 1] == escapeChar()) { 0156 ret += QString(escapeChar()); 0157 return 2; 0158 } 0159 typename QHash<QChar, VT>::const_iterator it = macromap.constFind(str.unicode()[pos + 1]); 0160 if (it != macromap.constEnd()) { 0161 ret += it.value(); 0162 return 2; 0163 } 0164 0165 return 0; 0166 } 0167 0168 template<typename VT> 0169 class KMacroMapExpander<QString, VT> : public KMacroExpanderBase 0170 { 0171 public: 0172 KMacroMapExpander(const QHash<QString, VT> &map, QChar c = QLatin1Char('%')) 0173 : KMacroExpanderBase(c) 0174 , macromap(map) 0175 { 0176 } 0177 0178 protected: 0179 int expandPlainMacro(const QString &str, int pos, QStringList &ret) override; 0180 int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override; 0181 0182 private: 0183 QHash<QString, VT> macromap; 0184 }; 0185 0186 template<typename VT> 0187 int KMacroMapExpander<QString, VT>::expandPlainMacro(const QString &str, int pos, QStringList &ret) 0188 { 0189 if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) { 0190 return 0; 0191 } 0192 int sl; 0193 for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++) { 0194 ; 0195 } 0196 if (!sl) { 0197 return 0; 0198 } 0199 typename QHash<QString, VT>::const_iterator it = macromap.constFind(str.mid(pos, sl)); 0200 if (it != macromap.constEnd()) { 0201 ret += it.value(); 0202 return sl; 0203 } 0204 return 0; 0205 } 0206 0207 template<typename VT> 0208 int KMacroMapExpander<QString, VT>::expandEscapedMacro(const QString &str, int pos, QStringList &ret) 0209 { 0210 if (str.length() <= pos + 1) { 0211 return 0; 0212 } 0213 0214 if (str.unicode()[pos + 1] == escapeChar()) { 0215 ret += QString(escapeChar()); 0216 return 2; 0217 } 0218 int sl; 0219 int rsl; 0220 int rpos; 0221 if (str.unicode()[pos + 1].unicode() == '{') { 0222 rpos = pos + 2; 0223 if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) { 0224 return 0; 0225 } 0226 sl -= rpos; 0227 rsl = sl + 3; 0228 } else { 0229 rpos = pos + 1; 0230 for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl) { 0231 ; 0232 } 0233 rsl = sl + 1; 0234 } 0235 if (!sl) { 0236 return 0; 0237 } 0238 typename QHash<QString, VT>::const_iterator it = macromap.constFind(str.mid(rpos, sl)); 0239 if (it != macromap.constEnd()) { 0240 ret += it.value(); 0241 return rsl; 0242 } 0243 return 0; 0244 } 0245 0246 //////////// 0247 0248 int KCharMacroExpander::expandPlainMacro(const QString &str, int pos, QStringList &ret) 0249 { 0250 if (expandMacro(str.unicode()[pos], ret)) { 0251 return 1; 0252 } 0253 return 0; 0254 } 0255 0256 int KCharMacroExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret) 0257 { 0258 if (str.length() <= pos + 1) { 0259 return 0; 0260 } 0261 0262 if (str.unicode()[pos + 1] == escapeChar()) { 0263 ret += QString(escapeChar()); 0264 return 2; 0265 } 0266 if (expandMacro(str.unicode()[pos + 1], ret)) { 0267 return 2; 0268 } 0269 return 0; 0270 } 0271 0272 int KWordMacroExpander::expandPlainMacro(const QString &str, int pos, QStringList &ret) 0273 { 0274 if (pos && isIdentifier(str.unicode()[pos - 1].unicode())) { 0275 return 0; 0276 } 0277 int sl; 0278 for (sl = 0; isIdentifier(str.unicode()[pos + sl].unicode()); sl++) { 0279 ; 0280 } 0281 if (!sl) { 0282 return 0; 0283 } 0284 if (expandMacro(str.mid(pos, sl), ret)) { 0285 return sl; 0286 } 0287 return 0; 0288 } 0289 0290 int KWordMacroExpander::expandEscapedMacro(const QString &str, int pos, QStringList &ret) 0291 { 0292 if (str.length() <= pos + 1) { 0293 return 0; 0294 } 0295 0296 if (str.unicode()[pos + 1] == escapeChar()) { 0297 ret += QString(escapeChar()); 0298 return 2; 0299 } 0300 int sl; 0301 int rsl; 0302 int rpos; 0303 if (str.unicode()[pos + 1].unicode() == '{') { 0304 rpos = pos + 2; 0305 if ((sl = str.indexOf(QLatin1Char('}'), rpos)) < 0) { 0306 return 0; 0307 } 0308 sl -= rpos; 0309 rsl = sl + 3; 0310 } else { 0311 rpos = pos + 1; 0312 for (sl = 0; isIdentifier(str.unicode()[rpos + sl].unicode()); ++sl) { 0313 ; 0314 } 0315 rsl = sl + 1; 0316 } 0317 if (!sl) { 0318 return 0; 0319 } 0320 if (expandMacro(str.mid(rpos, sl), ret)) { 0321 return rsl; 0322 } 0323 return 0; 0324 } 0325 0326 //////////// 0327 0328 template<typename KT, typename VT> 0329 inline QString TexpandMacros(const QString &ostr, const QHash<KT, VT> &map, QChar c) 0330 { 0331 QString str(ostr); 0332 KMacroMapExpander<KT, VT> kmx(map, c); 0333 kmx.expandMacros(str); 0334 return str; 0335 } 0336 0337 template<typename KT, typename VT> 0338 inline QString TexpandMacrosShellQuote(const QString &ostr, const QHash<KT, VT> &map, QChar c) 0339 { 0340 QString str(ostr); 0341 KMacroMapExpander<KT, VT> kmx(map, c); 0342 if (!kmx.expandMacrosShellQuote(str)) { 0343 return QString(); 0344 } 0345 return str; 0346 } 0347 0348 // public API 0349 namespace KMacroExpander 0350 { 0351 QString expandMacros(const QString &ostr, const QHash<QChar, QString> &map, QChar c) 0352 { 0353 return TexpandMacros(ostr, map, c); 0354 } 0355 QString expandMacrosShellQuote(const QString &ostr, const QHash<QChar, QString> &map, QChar c) 0356 { 0357 return TexpandMacrosShellQuote(ostr, map, c); 0358 } 0359 QString expandMacros(const QString &ostr, const QHash<QString, QString> &map, QChar c) 0360 { 0361 return TexpandMacros(ostr, map, c); 0362 } 0363 QString expandMacrosShellQuote(const QString &ostr, const QHash<QString, QString> &map, QChar c) 0364 { 0365 return TexpandMacrosShellQuote(ostr, map, c); 0366 } 0367 QString expandMacros(const QString &ostr, const QHash<QChar, QStringList> &map, QChar c) 0368 { 0369 return TexpandMacros(ostr, map, c); 0370 } 0371 QString expandMacrosShellQuote(const QString &ostr, const QHash<QChar, QStringList> &map, QChar c) 0372 { 0373 return TexpandMacrosShellQuote(ostr, map, c); 0374 } 0375 QString expandMacros(const QString &ostr, const QHash<QString, QStringList> &map, QChar c) 0376 { 0377 return TexpandMacros(ostr, map, c); 0378 } 0379 QString expandMacrosShellQuote(const QString &ostr, const QHash<QString, QStringList> &map, QChar c) 0380 { 0381 return TexpandMacrosShellQuote(ostr, map, c); 0382 } 0383 0384 } // namespace