1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the Qt Linguist of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** GNU General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU 19 ** General Public License version 3 as published by the Free Software 20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 21 ** included in the packaging of this file. Please review the following 22 ** information to ensure the GNU General Public License requirements will 23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 24 ** 25 ** $QT_END_LICENSE$ 26 ** 27 ****************************************************************************/ 28 29 #ifndef PROITEMS_H 30 #define PROITEMS_H 31 32 #include "qmake_global.h" 33 34 #include <qstring.h> 35 #include <qvector.h> 36 #include <qhash.h> 37 38 QT_BEGIN_NAMESPACE 39 40 class QTextStream; 41 42 #ifdef PROPARSER_THREAD_SAFE 43 typedef QAtomicInt ProItemRefCount; 44 #else 45 class ProItemRefCount { 46 public: m_cnt(cnt)47 ProItemRefCount(int cnt = 0) : m_cnt(cnt) {} ref()48 bool ref() { return ++m_cnt != 0; } deref()49 bool deref() { return --m_cnt != 0; } 50 ProItemRefCount &operator=(int value) { m_cnt = value; return *this; } 51 private: 52 int m_cnt; 53 }; 54 #endif 55 56 #ifndef QT_BUILD_QMAKE 57 # define PROITEM_EXPLICIT explicit 58 #else 59 # define PROITEM_EXPLICIT 60 #endif 61 62 class ProKey; 63 class ProStringList; 64 class ProFile; 65 66 class ProString { 67 public: 68 ProString(); 69 ProString(const ProString &other); 70 ProString &operator=(const ProString &) = default; 71 PROITEM_EXPLICIT ProString(const QString &str); 72 PROITEM_EXPLICIT ProString(const QStringRef &str); 73 PROITEM_EXPLICIT ProString(const char *str); 74 ProString(const QString &str, int offset, int length); 75 void setValue(const QString &str); clear()76 void clear() { m_string.clear(); m_length = 0; } setSource(const ProString & other)77 ProString &setSource(const ProString &other) { m_file = other.m_file; return *this; } setSource(int id)78 ProString &setSource(int id) { m_file = id; return *this; } sourceFile()79 int sourceFile() const { return m_file; } 80 81 ProString &prepend(const ProString &other); 82 ProString &append(const ProString &other, bool *pending = nullptr); append(const QString & other)83 ProString &append(const QString &other) { return append(ProString(other)); } 84 ProString &append(const QLatin1String other); append(const char * other)85 ProString &append(const char *other) { return append(QLatin1String(other)); } 86 ProString &append(QChar other); 87 ProString &append(const ProStringList &other, bool *pending = nullptr, bool skipEmpty1st = false); 88 ProString &operator+=(const ProString &other) { return append(other); } 89 ProString &operator+=(const QString &other) { return append(other); } 90 ProString &operator+=(const QLatin1String other) { return append(other); } 91 ProString &operator+=(const char *other) { return append(other); } 92 ProString &operator+=(QChar other) { return append(other); } 93 chop(int n)94 void chop(int n) { Q_ASSERT(n <= m_length); m_length -= n; } chopFront(int n)95 void chopFront(int n) { Q_ASSERT(n <= m_length); m_offset += n; m_length -= n; } 96 97 bool operator==(const ProString &other) const { return toQStringRef() == other.toQStringRef(); } 98 bool operator==(const QString &other) const { return toQStringRef() == other; } 99 bool operator==(const QStringRef &other) const { return toQStringRef() == other; } 100 bool operator==(QLatin1String other) const { return toQStringRef() == other; } 101 bool operator==(const char *other) const { return toQStringRef() == QLatin1String(other); } 102 bool operator!=(const ProString &other) const { return !(*this == other); } 103 bool operator!=(const QString &other) const { return !(*this == other); } 104 bool operator!=(QLatin1String other) const { return !(*this == other); } 105 bool operator!=(const char *other) const { return !(*this == other); } 106 bool operator<(const ProString &other) const { return toQStringRef() < other.toQStringRef(); } isNull()107 bool isNull() const { return m_string.isNull(); } isEmpty()108 bool isEmpty() const { return !m_length; } length()109 int length() const { return m_length; } size()110 int size() const { return m_length; } at(int i)111 QChar at(int i) const { Q_ASSERT((uint)i < (uint)m_length); return constData()[i]; } constData()112 const QChar *constData() const { return m_string.constData() + m_offset; } 113 ProString mid(int off, int len = -1) const; left(int len)114 ProString left(int len) const { return mid(0, len); } right(int len)115 ProString right(int len) const { return mid(qMax(0, size() - len)); } 116 ProString trimmed() const; 117 int compare(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub.toQStringRef(), cs); } 118 int compare(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub, cs); } 119 int compare(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(QLatin1String(sub), cs); } 120 bool startsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(sub.toQStringRef(), cs); } 121 bool startsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(sub, cs); } 122 bool startsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(QLatin1String(sub), cs); } 123 bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(c, cs); } 124 bool endsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(sub.toQStringRef(), cs); } 125 bool endsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(sub, cs); } 126 bool endsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(QLatin1String(sub), cs); } 127 bool endsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(c, cs); } 128 int indexOf(const QString &s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(s, from, cs); } 129 int indexOf(const char *s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(QLatin1String(s), from, cs); } 130 int indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(c, from, cs); } 131 int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(s, from, cs); } 132 int lastIndexOf(const char *s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(QLatin1String(s), from, cs); } 133 int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(c, from, cs); } 134 bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, 0, cs) >= 0; } 135 bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(QLatin1String(s), 0, cs) >= 0; } 136 bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, 0, cs) >= 0; } 137 int toLongLong(bool *ok = nullptr, int base = 10) const { return toQStringRef().toLongLong(ok, base); } 138 int toInt(bool *ok = nullptr, int base = 10) const { return toQStringRef().toInt(ok, base); } 139 short toShort(bool *ok = nullptr, int base = 10) const { return toQStringRef().toShort(ok, base); } 140 hash()141 uint hash() const { return m_hash; } 142 static uint hash(const QChar *p, int n); 143 toQStringRef()144 ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, m_offset, m_length); } toQStringView()145 ALWAYS_INLINE QStringView toQStringView() const { return QStringView(m_string).mid(m_offset, m_length); } 146 toKey()147 ALWAYS_INLINE ProKey &toKey() { return *(ProKey *)this; } toKey()148 ALWAYS_INLINE const ProKey &toKey() const { return *(const ProKey *)this; } 149 150 QString toQString() const; 151 QString &toQString(QString &tmp) const; 152 toLatin1()153 QByteArray toLatin1() const { return toQStringRef().toLatin1(); } 154 155 private: 156 ProString(const ProKey &other); 157 ProString &operator=(const ProKey &other); 158 159 enum OmitPreHashing { NoHash }; 160 ProString(const ProString &other, OmitPreHashing); 161 162 enum DoPreHashing { DoHash }; 163 ALWAYS_INLINE ProString(const QString &str, DoPreHashing); 164 ALWAYS_INLINE ProString(const char *str, DoPreHashing); 165 ALWAYS_INLINE ProString(const QString &str, int offset, int length, DoPreHashing); 166 ALWAYS_INLINE ProString(const QString &str, int offset, int length, uint hash); 167 168 QString m_string; 169 int m_offset, m_length; 170 int m_file; 171 mutable uint m_hash; 172 QChar *prepareExtend(int extraLen, int thisTarget, int extraTarget); 173 uint updatedHash() const; 174 friend uint qHash(const ProString &str); 175 friend QString operator+(const ProString &one, const ProString &two); 176 friend class ProKey; 177 }; 178 Q_DECLARE_TYPEINFO(ProString, Q_MOVABLE_TYPE); 179 180 class ProKey : public ProString { 181 public: ProKey()182 ALWAYS_INLINE ProKey() : ProString() {} 183 explicit ProKey(const QString &str); 184 PROITEM_EXPLICIT ProKey(const char *str); 185 ProKey(const QString &str, int off, int len); 186 ProKey(const QString &str, int off, int len, uint hash); 187 void setValue(const QString &str); 188 189 #ifdef Q_CC_MSVC 190 // Workaround strange MSVC behaviour when exporting classes with ProKey members. ProKey(const ProKey & other)191 ALWAYS_INLINE ProKey(const ProKey &other) : ProString(other.toString()) {} 192 ALWAYS_INLINE ProKey &operator=(const ProKey &other) 193 { 194 toString() = other.toString(); 195 return *this; 196 } 197 #endif 198 toString()199 ALWAYS_INLINE ProString &toString() { return *(ProString *)this; } toString()200 ALWAYS_INLINE const ProString &toString() const { return *(const ProString *)this; } 201 202 private: 203 ProKey(const ProString &other); 204 }; 205 Q_DECLARE_TYPEINFO(ProKey, Q_MOVABLE_TYPE); 206 207 uint qHash(const ProString &str); 208 QString operator+(const ProString &one, const ProString &two); 209 inline QString operator+(const ProString &one, const QString &two) 210 { return one.toQStringRef() + two; } 211 inline QString operator+(const QString &one, const ProString &two) 212 { return one + two.toQStringRef(); } 213 214 inline QString operator+(const ProString &one, const char *two) 215 { return one.toQStringRef() + QLatin1String(two); } 216 inline QString operator+(const char *one, const ProString &two) 217 { return QLatin1String(one) + two.toQStringRef(); } 218 inline QString operator+(const ProString &one, QChar two) 219 { return one.toQStringRef() + two; } 220 inline QString operator+(QChar one, const ProString &two) 221 { return one + two.toQStringRef(); } 222 223 inline QString &operator+=(QString &that, const ProString &other) 224 { return that += other.toQStringRef(); } 225 226 inline bool operator==(const QString &that, const ProString &other) 227 { return other == that; } 228 inline bool operator!=(const QString &that, const ProString &other) 229 { return !(other == that); } 230 231 QTextStream &operator<<(QTextStream &t, const ProString &str); 232 233 // This class manages read-only access to a ProString via a raw data QString 234 // temporary, ensuring that the latter is accessed exclusively. 235 class ProStringRoUser 236 { 237 public: ProStringRoUser(QString & rs)238 ProStringRoUser(QString &rs) 239 { 240 Q_ASSERT(rs.isDetached() || rs.isEmpty()); 241 m_rs = &rs; 242 } ProStringRoUser(const ProString & ps,QString & rs)243 ProStringRoUser(const ProString &ps, QString &rs) 244 : ProStringRoUser(rs) 245 { 246 ps.toQString(rs); 247 } 248 // No destructor, as a RAII pattern cannot be used: references to the 249 // temporary string can legitimately outlive instances of this class 250 // (if they are held by Qt, e.g. in QRegExp). set(const ProString & ps)251 QString &set(const ProString &ps) { return ps.toQString(*m_rs); } str()252 QString &str() { return *m_rs; } 253 254 protected: 255 QString *m_rs; 256 }; 257 258 // This class manages read-write access to a ProString via a raw data QString 259 // temporary, ensuring that the latter is accessed exclusively, and that raw 260 // data does not leak outside its source's refcounting. 261 class ProStringRwUser : public ProStringRoUser 262 { 263 public: ProStringRwUser(QString & rs)264 ProStringRwUser(QString &rs) 265 : ProStringRoUser(rs), m_ps(nullptr) {} ProStringRwUser(const ProString & ps,QString & rs)266 ProStringRwUser(const ProString &ps, QString &rs) 267 : ProStringRoUser(ps, rs), m_ps(&ps) {} set(const ProString & ps)268 QString &set(const ProString &ps) { m_ps = &ps; return ProStringRoUser::set(ps); } extract(const QString & s)269 ProString extract(const QString &s) const 270 { return s.isSharedWith(*m_rs) ? *m_ps : ProString(s).setSource(*m_ps); } extract(const QString & s,const ProStringRwUser & other)271 ProString extract(const QString &s, const ProStringRwUser &other) const 272 { 273 if (other.m_ps && s.isSharedWith(*other.m_rs)) 274 return *other.m_ps; 275 return extract(s); 276 } 277 278 private: 279 const ProString *m_ps; 280 }; 281 282 class ProStringList : public QVector<ProString> { 283 public: ProStringList()284 ProStringList() {} ProStringList(const ProString & str)285 ProStringList(const ProString &str) { *this << str; } 286 explicit ProStringList(const QStringList &list); 287 QStringList toQStringList() const; 288 289 ProStringList &operator<<(const ProString &str) 290 { QVector<ProString>::operator<<(str); return *this; } 291 length()292 int length() const { return size(); } 293 294 QString join(const ProString &sep) const; 295 QString join(const QString &sep) const; 296 QString join(QChar sep) const; 297 298 void insertUnique(const ProStringList &value); 299 300 void removeAll(const ProString &str); 301 void removeAll(const char *str); 302 void removeEach(const ProStringList &value); removeAt(int idx)303 void removeAt(int idx) { remove(idx); } 304 void removeEmpty(); 305 void removeDuplicates(); 306 307 bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; 308 bool contains(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; 309 bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const 310 { return contains(ProString(str), cs); } 311 bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; 312 }; 313 Q_DECLARE_TYPEINFO(ProStringList, Q_MOVABLE_TYPE); 314 315 inline ProStringList operator+(const ProStringList &one, const ProStringList &two) 316 { ProStringList ret = one; ret += two; return ret; } 317 318 typedef QHash<ProKey, ProStringList> ProValueMap; 319 320 // These token definitions affect both ProFileEvaluator and ProWriter 321 enum ProToken { 322 TokTerminator = 0, // end of stream (possibly not included in length; must be zero) 323 TokLine, // line marker: 324 // - line (1) 325 TokAssign, // variable = 326 TokAppend, // variable += 327 TokAppendUnique, // variable *= 328 TokRemove, // variable -= 329 TokReplace, // variable ~= 330 // previous literal/expansion is a variable manipulation 331 // - lower bound for expected output length (1) 332 // - value expression + TokValueTerminator 333 TokValueTerminator, // assignment value terminator 334 TokLiteral, // literal string (fully dequoted) 335 // - length (1) 336 // - string data (length; unterminated) 337 TokHashLiteral, // literal string with hash (fully dequoted) 338 // - hash (2) 339 // - length (1) 340 // - string data (length; unterminated) 341 TokVariable, // qmake variable expansion 342 // - hash (2) 343 // - name length (1) 344 // - name (name length; unterminated) 345 TokProperty, // qmake property expansion 346 // - hash (2) 347 // - name length (1) 348 // - name (name length; unterminated) 349 TokEnvVar, // environment variable expansion 350 // - name length (1) 351 // - name (name length; unterminated) 352 TokFuncName, // replace function expansion 353 // - hash (2) 354 // - name length (1) 355 // - name (name length; unterminated) 356 // - ((nested expansion + TokArgSeparator)* + nested expansion)? 357 // - TokFuncTerminator 358 TokArgSeparator, // function argument separator 359 TokFuncTerminator, // function argument list terminator 360 TokCondition, // previous literal/expansion is a conditional 361 TokTestCall, // previous literal/expansion is a test function call 362 // - ((nested expansion + TokArgSeparator)* + nested expansion)? 363 // - TokFuncTerminator 364 TokReturn, // previous literal/expansion is a return value 365 TokBreak, // break loop 366 TokNext, // shortcut to next loop iteration 367 TokNot, // '!' operator 368 TokAnd, // ':' operator 369 TokOr, // '|' operator 370 TokBranch, // branch point: 371 // - then block length (2) 372 // - then block + TokTerminator (then block length) 373 // - else block length (2) 374 // - else block + TokTerminator (else block length) 375 TokForLoop, // for loop: 376 // - variable name: hash (2), length (1), chars (length) 377 // - expression: length (2), bytes + TokValueTerminator (length) 378 // - body length (2) 379 // - body + TokTerminator (body length) 380 TokTestDef, // test function definition: 381 TokReplaceDef, // replace function definition: 382 // - function name: hash (2), length (1), chars (length) 383 // - body length (2) 384 // - body + TokTerminator (body length) 385 TokBypassNesting, // escape from function local variable scopes: 386 // - block length (2) 387 // - block + TokTerminator (block length) 388 TokMask = 0xff, 389 TokQuoted = 0x100, // The expression is quoted => join expanded stringlist 390 TokNewStr = 0x200 // Next stringlist element 391 }; 392 393 class QMAKE_EXPORT ProFile 394 { 395 public: 396 ProFile(int id, const QString &fileName); 397 ~ProFile(); 398 id()399 int id() const { return m_id; } fileName()400 QString fileName() const { return m_fileName; } directoryName()401 QString directoryName() const { return m_directoryName; } items()402 const QString &items() const { return m_proitems; } itemsRef()403 QString *itemsRef() { return &m_proitems; } tokPtr()404 const ushort *tokPtr() const { return (const ushort *)m_proitems.constData(); } tokPtrEnd()405 const ushort *tokPtrEnd() const { return (const ushort *)m_proitems.constData() + m_proitems.size(); } 406 ref()407 void ref() { m_refCount.ref(); } deref()408 void deref() { if (!m_refCount.deref()) delete this; } 409 isOk()410 bool isOk() const { return m_ok; } setOk(bool ok)411 void setOk(bool ok) { m_ok = ok; } 412 isHostBuild()413 bool isHostBuild() const { return m_hostBuild; } setHostBuild(bool host_build)414 void setHostBuild(bool host_build) { m_hostBuild = host_build; } 415 416 ProString getStr(const ushort *&tPtr); 417 ProKey getHashStr(const ushort *&tPtr); 418 419 private: 420 ProItemRefCount m_refCount; 421 QString m_proitems; 422 QString m_fileName; 423 QString m_directoryName; 424 int m_id; 425 bool m_ok; 426 bool m_hostBuild; 427 }; 428 429 class ProFunctionDef { 430 public: ProFunctionDef(ProFile * pro,int offset)431 ProFunctionDef(ProFile *pro, int offset) : m_pro(pro), m_offset(offset) { m_pro->ref(); } ProFunctionDef(const ProFunctionDef & o)432 ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); } ProFunctionDef(ProFunctionDef && other)433 ProFunctionDef(ProFunctionDef &&other) Q_DECL_NOTHROW 434 : m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; } ~ProFunctionDef()435 ~ProFunctionDef() { if (m_pro) m_pro->deref(); } 436 ProFunctionDef &operator=(const ProFunctionDef &o) 437 { 438 if (this != &o) { 439 if (m_pro) 440 m_pro->deref(); 441 m_pro = o.m_pro; 442 m_pro->ref(); 443 m_offset = o.m_offset; 444 } 445 return *this; 446 } 447 ProFunctionDef &operator=(ProFunctionDef &&other) Q_DECL_NOTHROW 448 { 449 ProFunctionDef moved(std::move(other)); 450 swap(moved); 451 return *this; 452 } swap(ProFunctionDef & other)453 void swap(ProFunctionDef &other) Q_DECL_NOTHROW 454 { 455 qSwap(m_pro, other.m_pro); 456 qSwap(m_offset, other.m_offset); 457 } 458 pro()459 ProFile *pro() const { return m_pro; } tokPtr()460 const ushort *tokPtr() const { return m_pro->tokPtr() + m_offset; } 461 private: 462 ProFile *m_pro; 463 int m_offset; 464 }; 465 466 Q_DECLARE_TYPEINFO(ProFunctionDef, Q_MOVABLE_TYPE); 467 468 struct ProFunctionDefs { 469 QHash<ProKey, ProFunctionDef> testFunctions; 470 QHash<ProKey, ProFunctionDef> replaceFunctions; 471 }; 472 473 QT_END_NAMESPACE 474 475 #endif // PROITEMS_H 476