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

source code of qttools/src/linguist/shared/proitems.h