| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the qmake application of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #ifndef PROITEMS_H |
| #define PROITEMS_H |
| |
| #include "qmake_global.h" |
| |
| #include <qdebug.h> |
| #include <qstring.h> |
| #include <qvector.h> |
| #include <qhash.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| class QTextStream; |
| |
| #ifdef PROPARSER_THREAD_SAFE |
| typedef QAtomicInt ProItemRefCount; |
| #else |
| class ProItemRefCount { |
| public: |
| ProItemRefCount(int cnt = 0) : m_cnt(cnt) {} |
| bool ref() { return ++m_cnt != 0; } |
| bool deref() { return --m_cnt != 0; } |
| ProItemRefCount &operator=(int value) { m_cnt = value; return *this; } |
| private: |
| int m_cnt; |
| }; |
| #endif |
| |
| #ifndef QT_BUILD_QMAKE |
| # define PROITEM_EXPLICIT explicit |
| #else |
| # define PROITEM_EXPLICIT |
| #endif |
| |
| class ProKey; |
| class ProStringList; |
| class ProFile; |
| |
| class ProString { |
| public: |
| ProString(); |
| ProString(const ProString &other); |
| ProString &operator=(const ProString &) = default; |
| PROITEM_EXPLICIT ProString(const QString &str); |
| PROITEM_EXPLICIT ProString(const QStringRef &str); |
| PROITEM_EXPLICIT ProString(const char *str); |
| ProString(const QString &str, int offset, int length); |
| void setValue(const QString &str); |
| void clear() { m_string.clear(); m_length = 0; } |
| ProString &setSource(const ProString &other) { m_file = other.m_file; return *this; } |
| ProString &setSource(int id) { m_file = id; return *this; } |
| int sourceFile() const { return m_file; } |
| |
| ProString &prepend(const ProString &other); |
| ProString &append(const ProString &other, bool *pending = nullptr); |
| ProString &append(const QString &other) { return append(ProString(other)); } |
| ProString &append(const QLatin1String other); |
| ProString &append(const char *other) { return append(QLatin1String(other)); } |
| ProString &append(QChar other); |
| ProString &append(const ProStringList &other, bool *pending = nullptr, bool skipEmpty1st = false); |
| ProString &operator+=(const ProString &other) { return append(other); } |
| ProString &operator+=(const QString &other) { return append(other); } |
| ProString &operator+=(const QLatin1String other) { return append(other); } |
| ProString &operator+=(const char *other) { return append(other); } |
| ProString &operator+=(QChar other) { return append(other); } |
| |
| void chop(int n) { Q_ASSERT(n <= m_length); m_length -= n; } |
| void chopFront(int n) { Q_ASSERT(n <= m_length); m_offset += n; m_length -= n; } |
| |
| bool operator==(const ProString &other) const { return toQStringRef() == other.toQStringRef(); } |
| bool operator==(const QString &other) const { return toQStringRef() == other; } |
| bool operator==(const QStringRef &other) const { return toQStringRef() == other; } |
| bool operator==(QLatin1String other) const { return toQStringRef() == other; } |
| bool operator==(const char *other) const { return toQStringRef() == QLatin1String(other); } |
| bool operator!=(const ProString &other) const { return !(*this == other); } |
| bool operator!=(const QString &other) const { return !(*this == other); } |
| bool operator!=(QLatin1String other) const { return !(*this == other); } |
| bool operator!=(const char *other) const { return !(*this == other); } |
| bool operator<(const ProString &other) const { return toQStringRef() < other.toQStringRef(); } |
| bool isNull() const { return m_string.isNull(); } |
| bool isEmpty() const { return !m_length; } |
| int length() const { return m_length; } |
| int size() const { return m_length; } |
| QChar at(int i) const { Q_ASSERT((uint)i < (uint)m_length); return constData()[i]; } |
| const QChar *constData() const { return m_string.constData() + m_offset; } |
| ProString mid(int off, int len = -1) const; |
| ProString left(int len) const { return mid(0, len); } |
| ProString right(int len) const { return mid(qMax(0, size() - len)); } |
| ProString trimmed() const; |
| int compare(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub.toQStringRef(), cs); } |
| int compare(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub, cs); } |
| int compare(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(QLatin1String(sub), cs); } |
| bool startsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(sub.toQStringRef(), cs); } |
| bool startsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(sub, cs); } |
| bool startsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(QLatin1String(sub), cs); } |
| bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(c, cs); } |
| bool endsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(sub.toQStringRef(), cs); } |
| bool endsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(sub, cs); } |
| bool endsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(QLatin1String(sub), cs); } |
| bool endsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(c, cs); } |
| int indexOf(const QString &s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(s, from, cs); } |
| int indexOf(const char *s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(QLatin1String(s), from, cs); } |
| int indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(c, from, cs); } |
| int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(s, from, cs); } |
| int lastIndexOf(const char *s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(QLatin1String(s), from, cs); } |
| int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(c, from, cs); } |
| bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, 0, cs) >= 0; } |
| bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(QLatin1String(s), 0, cs) >= 0; } |
| bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, 0, cs) >= 0; } |
| qlonglong toLongLong(bool *ok = nullptr, int base = 10) const { return toQStringRef().toLongLong(ok, base); } |
| int toInt(bool *ok = nullptr, int base = 10) const { return toQStringRef().toInt(ok, base); } |
| short toShort(bool *ok = nullptr, int base = 10) const { return toQStringRef().toShort(ok, base); } |
| |
| uint hash() const { return m_hash; } |
| static uint hash(const QChar *p, int n); |
| |
| ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, m_offset, m_length); } |
| ALWAYS_INLINE QStringView toQStringView() const { return QStringView(m_string).mid(m_offset, m_length); } |
| |
| ALWAYS_INLINE ProKey &toKey() { return *(ProKey *)this; } |
| ALWAYS_INLINE const ProKey &toKey() const { return *(const ProKey *)this; } |
| |
| QString toQString() const; |
| QString &toQString(QString &tmp) const; |
| |
| QByteArray toLatin1() const { return toQStringRef().toLatin1(); } |
| |
| private: |
| ProString(const ProKey &other); |
| ProString &operator=(const ProKey &other); |
| |
| enum OmitPreHashing { NoHash }; |
| ProString(const ProString &other, OmitPreHashing); |
| |
| enum DoPreHashing { DoHash }; |
| ALWAYS_INLINE ProString(const QString &str, DoPreHashing); |
| ALWAYS_INLINE ProString(const char *str, DoPreHashing); |
| ALWAYS_INLINE ProString(const QString &str, int offset, int length, DoPreHashing); |
| ALWAYS_INLINE ProString(const QString &str, int offset, int length, uint hash); |
| |
| QString m_string; |
| int m_offset, m_length; |
| int m_file; |
| mutable uint m_hash; |
| QChar *prepareExtend(int extraLen, int thisTarget, int extraTarget); |
| uint updatedHash() const; |
| friend uint qHash(const ProString &str); |
| friend QString operator+(const ProString &one, const ProString &two); |
| friend class ProKey; |
| }; |
| Q_DECLARE_TYPEINFO(ProString, Q_MOVABLE_TYPE); |
| |
| class ProKey : public ProString { |
| public: |
| ALWAYS_INLINE ProKey() : ProString() {} |
| explicit ProKey(const QString &str); |
| PROITEM_EXPLICIT ProKey(const char *str); |
| ProKey(const QString &str, int off, int len); |
| ProKey(const QString &str, int off, int len, uint hash); |
| void setValue(const QString &str); |
| |
| #ifdef Q_CC_MSVC |
| // Workaround strange MSVC behaviour when exporting classes with ProKey members. |
| ALWAYS_INLINE ProKey(const ProKey &other) : ProString(other.toString()) {} |
| ALWAYS_INLINE ProKey &operator=(const ProKey &other) |
| { |
| toString() = other.toString(); |
| return *this; |
| } |
| #endif |
| |
| ALWAYS_INLINE ProString &toString() { return *(ProString *)this; } |
| ALWAYS_INLINE const ProString &toString() const { return *(const ProString *)this; } |
| |
| private: |
| ProKey(const ProString &other); |
| }; |
| Q_DECLARE_TYPEINFO(ProKey, Q_MOVABLE_TYPE); |
| |
| uint qHash(const ProString &str); |
| QString operator+(const ProString &one, const ProString &two); |
| inline QString operator+(const ProString &one, const QString &two) |
| { return one.toQStringRef() + two; } |
| inline QString operator+(const QString &one, const ProString &two) |
| { return one + two.toQStringRef(); } |
| |
| inline QString operator+(const ProString &one, const char *two) |
| { return one.toQStringRef() + QLatin1String(two); } |
| inline QString operator+(const char *one, const ProString &two) |
| { return QLatin1String(one) + two.toQStringRef(); } |
| inline QString operator+(const ProString &one, QChar two) |
| { return one.toQStringRef() + two; } |
| inline QString operator+(QChar one, const ProString &two) |
| { return one + two.toQStringRef(); } |
| |
| inline QString &operator+=(QString &that, const ProString &other) |
| { return that += other.toQStringRef(); } |
| |
| inline bool operator==(const QString &that, const ProString &other) |
| { return other == that; } |
| inline bool operator!=(const QString &that, const ProString &other) |
| { return !(other == that); } |
| |
| QTextStream &operator<<(QTextStream &t, const ProString &str); |
| |
| // This class manages read-only access to a ProString via a raw data QString |
| // temporary, ensuring that the latter is accessed exclusively. |
| class ProStringRoUser |
| { |
| public: |
| ProStringRoUser(QString &rs) |
| { |
| Q_ASSERT(rs.isDetached() || rs.isEmpty()); |
| m_rs = &rs; |
| } |
| ProStringRoUser(const ProString &ps, QString &rs) |
| : ProStringRoUser(rs) |
| { |
| ps.toQString(rs); |
| } |
| // No destructor, as a RAII pattern cannot be used: references to the |
| // temporary string can legitimately outlive instances of this class |
| // (if they are held by Qt, e.g. in QRegExp). |
| QString &set(const ProString &ps) { return ps.toQString(*m_rs); } |
| QString &str() { return *m_rs; } |
| |
| protected: |
| QString *m_rs; |
| }; |
| |
| // This class manages read-write access to a ProString via a raw data QString |
| // temporary, ensuring that the latter is accessed exclusively, and that raw |
| // data does not leak outside its source's refcounting. |
| class ProStringRwUser : public ProStringRoUser |
| { |
| public: |
| ProStringRwUser(QString &rs) |
| : ProStringRoUser(rs), m_ps(nullptr) {} |
| ProStringRwUser(const ProString &ps, QString &rs) |
| : ProStringRoUser(ps, rs), m_ps(&ps) {} |
| QString &set(const ProString &ps) { m_ps = &ps; return ProStringRoUser::set(ps); } |
| ProString extract(const QString &s) const |
| { return s.isSharedWith(*m_rs) ? *m_ps : ProString(s).setSource(*m_ps); } |
| ProString extract(const QString &s, const ProStringRwUser &other) const |
| { |
| if (other.m_ps && s.isSharedWith(*other.m_rs)) |
| return *other.m_ps; |
| return extract(s); |
| } |
| |
| private: |
| const ProString *m_ps; |
| }; |
| |
| class ProStringList : public QVector<ProString> { |
| public: |
| ProStringList() {} |
| ProStringList(const ProString &str) { *this << str; } |
| explicit ProStringList(const QStringList &list); |
| QStringList toQStringList() const; |
| |
| ProStringList &operator<<(const ProString &str) |
| { QVector<ProString>::operator<<(str); return *this; } |
| |
| int length() const { return size(); } |
| |
| QString join(const ProString &sep) const; |
| QString join(const QString &sep) const; |
| QString join(QChar sep) const; |
| |
| void insertUnique(const ProStringList &value); |
| |
| void removeAll(const ProString &str); |
| void removeAll(const char *str); |
| void removeEach(const ProStringList &value); |
| void removeAt(int idx) { remove(idx); } |
| void removeEmpty(); |
| void removeDuplicates(); |
| |
| bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; |
| bool contains(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; |
| bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const |
| { return contains(ProString(str), cs); } |
| bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; |
| }; |
| Q_DECLARE_TYPEINFO(ProStringList, Q_MOVABLE_TYPE); |
| |
| inline ProStringList operator+(const ProStringList &one, const ProStringList &two) |
| { ProStringList ret = one; ret += two; return ret; } |
| |
| typedef QHash<ProKey, ProStringList> ProValueMap; |
| |
| // These token definitions affect both ProFileEvaluator and ProWriter |
| enum ProToken { |
| TokTerminator = 0, // end of stream (possibly not included in length; must be zero) |
| TokLine, // line marker: |
| // - line (1) |
| TokAssign, // variable = |
| TokAppend, // variable += |
| TokAppendUnique, // variable *= |
| TokRemove, // variable -= |
| TokReplace, // variable ~= |
| // previous literal/expansion is a variable manipulation |
| // - lower bound for expected output length (1) |
| // - value expression + TokValueTerminator |
| TokValueTerminator, // assignment value terminator |
| TokLiteral, // literal string (fully dequoted) |
| // - length (1) |
| // - string data (length; unterminated) |
| TokHashLiteral, // literal string with hash (fully dequoted) |
| // - hash (2) |
| // - length (1) |
| // - string data (length; unterminated) |
| TokVariable, // qmake variable expansion |
| // - hash (2) |
| // - name length (1) |
| // - name (name length; unterminated) |
| TokProperty, // qmake property expansion |
| // - hash (2) |
| // - name length (1) |
| // - name (name length; unterminated) |
| TokEnvVar, // environment variable expansion |
| // - name length (1) |
| // - name (name length; unterminated) |
| TokFuncName, // replace function expansion |
| // - hash (2) |
| // - name length (1) |
| // - name (name length; unterminated) |
| // - ((nested expansion + TokArgSeparator)* + nested expansion)? |
| // - TokFuncTerminator |
| TokArgSeparator, // function argument separator |
| TokFuncTerminator, // function argument list terminator |
| TokCondition, // previous literal/expansion is a conditional |
| TokTestCall, // previous literal/expansion is a test function call |
| // - ((nested expansion + TokArgSeparator)* + nested expansion)? |
| // - TokFuncTerminator |
| TokReturn, // previous literal/expansion is a return value |
| TokBreak, // break loop |
| TokNext, // shortcut to next loop iteration |
| TokNot, // '!' operator |
| TokAnd, // ':' operator |
| TokOr, // '|' operator |
| TokBranch, // branch point: |
| // - then block length (2) |
| // - then block + TokTerminator (then block length) |
| // - else block length (2) |
| // - else block + TokTerminator (else block length) |
| TokForLoop, // for loop: |
| // - variable name: hash (2), length (1), chars (length) |
| // - expression: length (2), bytes + TokValueTerminator (length) |
| // - body length (2) |
| // - body + TokTerminator (body length) |
| TokTestDef, // test function definition: |
| TokReplaceDef, // replace function definition: |
| // - function name: hash (2), length (1), chars (length) |
| // - body length (2) |
| // - body + TokTerminator (body length) |
| TokBypassNesting, // escape from function local variable scopes: |
| // - block length (2) |
| // - block + TokTerminator (block length) |
| TokMask = 0xff, |
| TokQuoted = 0x100, // The expression is quoted => join expanded stringlist |
| TokNewStr = 0x200 // Next stringlist element |
| }; |
| |
| class QMAKE_EXPORT ProFile |
| { |
| public: |
| ProFile(int id, const QString &fileName); |
| ~ProFile(); |
| |
| int id() const { return m_id; } |
| QString fileName() const { return m_fileName; } |
| QString directoryName() const { return m_directoryName; } |
| const QString &items() const { return m_proitems; } |
| QString *itemsRef() { return &m_proitems; } |
| const ushort *tokPtr() const { return (const ushort *)m_proitems.constData(); } |
| const ushort *tokPtrEnd() const { return (const ushort *)m_proitems.constData() + m_proitems.size(); } |
| |
| void ref() { m_refCount.ref(); } |
| void deref() { if (!m_refCount.deref()) delete this; } |
| |
| bool isOk() const { return m_ok; } |
| void setOk(bool ok) { m_ok = ok; } |
| |
| bool isHostBuild() const { return m_hostBuild; } |
| void setHostBuild(bool host_build) { m_hostBuild = host_build; } |
| |
| ProString getStr(const ushort *&tPtr); |
| ProKey getHashStr(const ushort *&tPtr); |
| |
| private: |
| ProItemRefCount m_refCount; |
| QString m_proitems; |
| QString m_fileName; |
| QString m_directoryName; |
| int m_id; |
| bool m_ok; |
| bool m_hostBuild; |
| }; |
| |
| class ProFunctionDef { |
| public: |
| ProFunctionDef(ProFile *pro, int offset) : m_pro(pro), m_offset(offset) { m_pro->ref(); } |
| ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); } |
| ProFunctionDef(ProFunctionDef &&other) noexcept |
| : m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; } |
| ~ProFunctionDef() { if (m_pro) m_pro->deref(); } |
| ProFunctionDef &operator=(const ProFunctionDef &o) |
| { |
| if (this != &o) { |
| if (m_pro) |
| m_pro->deref(); |
| m_pro = o.m_pro; |
| m_pro->ref(); |
| m_offset = o.m_offset; |
| } |
| return *this; |
| } |
| ProFunctionDef &operator=(ProFunctionDef &&other) noexcept |
| { |
| ProFunctionDef moved(std::move(other)); |
| swap(moved); |
| return *this; |
| } |
| void swap(ProFunctionDef &other) noexcept |
| { |
| qSwap(m_pro, other.m_pro); |
| qSwap(m_offset, other.m_offset); |
| } |
| |
| ProFile *pro() const { return m_pro; } |
| const ushort *tokPtr() const { return m_pro->tokPtr() + m_offset; } |
| private: |
| ProFile *m_pro; |
| int m_offset; |
| }; |
| |
| Q_DECLARE_TYPEINFO(ProFunctionDef, Q_MOVABLE_TYPE); |
| |
| struct ProFunctionDefs { |
| QHash<ProKey, ProFunctionDef> testFunctions; |
| QHash<ProKey, ProFunctionDef> replaceFunctions; |
| }; |
| |
| QDebug operator<<(QDebug debug, const ProString &str); |
| |
| QT_END_NAMESPACE |
| |
| #endif // PROITEMS_H |