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