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