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 | #include "proitems.h" |
30 | |
31 | #include <qfileinfo.h> |
32 | #include <qset.h> |
33 | #include <qstringlist.h> |
34 | #include <qtextstream.h> |
35 | #include <private/qduplicatetracker_p.h> |
36 | |
37 | QT_BEGIN_NAMESPACE |
38 | |
39 | // from qhash.cpp |
40 | size_t ProString::hash(const QChar *p, int n) |
41 | { |
42 | size_t h = 0; |
43 | |
44 | while (n--) { |
45 | h = (h << 4) + (*p++).unicode(); |
46 | h ^= (h & 0xf0000000) >> 23; |
47 | h &= 0x0fffffff; |
48 | } |
49 | return h; |
50 | } |
51 | |
52 | ProString::ProString() : |
53 | m_offset(0), m_length(0), m_file(0), m_hash(0x80000000) |
54 | { |
55 | } |
56 | |
57 | ProString::ProString(const ProString &other) : |
58 | m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(other.m_hash) |
59 | { |
60 | } |
61 | |
62 | ProString::ProString(const ProString &other, OmitPreHashing) : |
63 | m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(0x80000000) |
64 | { |
65 | } |
66 | |
67 | ProString::ProString(const QString &str, DoPreHashing) : |
68 | m_string(str), m_offset(0), m_length(str.length()), m_file(0) |
69 | { |
70 | updatedHash(); |
71 | } |
72 | |
73 | ProString::ProString(const QString &str) : |
74 | m_string(str), m_offset(0), m_length(str.length()), m_file(0), m_hash(0x80000000) |
75 | { |
76 | } |
77 | |
78 | ProString::ProString(QStringView str) : |
79 | m_string(str.toString()), m_offset(0), m_length(str.size()), m_file(0), m_hash(0x80000000) |
80 | { |
81 | } |
82 | |
83 | ProString::ProString(const char *str, DoPreHashing) : |
84 | m_string(QString::fromLatin1(str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0) |
85 | { |
86 | updatedHash(); |
87 | } |
88 | |
89 | ProString::ProString(const char *str) : |
90 | m_string(QString::fromLatin1(str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0), m_hash(0x80000000) |
91 | { |
92 | } |
93 | |
94 | ProString::ProString(const QString &str, int offset, int length, DoPreHashing) : |
95 | m_string(str), m_offset(offset), m_length(length), m_file(0) |
96 | { |
97 | updatedHash(); |
98 | } |
99 | |
100 | ProString::ProString(const QString &str, int offset, int length, uint hash) : |
101 | m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(hash) |
102 | { |
103 | } |
104 | |
105 | ProString::ProString(const QString &str, int offset, int length) : |
106 | m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(0x80000000) |
107 | { |
108 | } |
109 | |
110 | void ProString::setValue(const QString &str) |
111 | { |
112 | m_string = str, m_offset = 0, m_length = str.length(), m_hash = 0x80000000; |
113 | } |
114 | |
115 | size_t ProString::updatedHash() const |
116 | { |
117 | return (m_hash = hash(m_string.constData() + m_offset, m_length)); |
118 | } |
119 | |
120 | size_t qHash(const ProString &str) |
121 | { |
122 | if (!(str.m_hash & 0x80000000)) |
123 | return str.m_hash; |
124 | return str.updatedHash(); |
125 | } |
126 | |
127 | ProKey::ProKey(const QString &str) : |
128 | ProString(str, DoHash) |
129 | { |
130 | } |
131 | |
132 | ProKey::ProKey(const char *str) : |
133 | ProString(str, DoHash) |
134 | { |
135 | } |
136 | |
137 | ProKey::ProKey(const QString &str, int off, int len) : |
138 | ProString(str, off, len, DoHash) |
139 | { |
140 | } |
141 | |
142 | ProKey::ProKey(const QString &str, int off, int len, uint hash) : |
143 | ProString(str, off, len, hash) |
144 | { |
145 | } |
146 | |
147 | void ProKey::setValue(const QString &str) |
148 | { |
149 | m_string = str, m_offset = 0, m_length = str.length(); |
150 | updatedHash(); |
151 | } |
152 | |
153 | QString ProString::toQString() const |
154 | { |
155 | return m_string.mid(m_offset, m_length); |
156 | } |
157 | |
158 | QString &ProString::toQString(QString &tmp) const |
159 | { |
160 | tmp = m_string.mid(m_offset, m_length); |
161 | return tmp; |
162 | } |
163 | |
164 | ProString &ProString::prepend(const ProString &other) |
165 | { |
166 | if (other.m_length) { |
167 | if (!m_length) { |
168 | *this = other; |
169 | } else { |
170 | m_string = other.toQStringView() + toQStringView(); |
171 | m_offset = 0; |
172 | m_length = m_string.length(); |
173 | if (!m_file) |
174 | m_file = other.m_file; |
175 | m_hash = 0x80000000; |
176 | } |
177 | } |
178 | return *this; |
179 | } |
180 | |
181 | ProString &ProString::append(const QLatin1String other) |
182 | { |
183 | if (other.size()) { |
184 | if (m_length != m_string.length()) { |
185 | m_string = toQStringView() + other; |
186 | m_offset = 0; |
187 | m_length = m_string.length(); |
188 | } else { |
189 | Q_ASSERT(m_offset == 0); |
190 | m_string.append(other); |
191 | m_length += other.size(); |
192 | } |
193 | m_hash = 0x80000000; |
194 | } |
195 | return *this; |
196 | } |
197 | |
198 | ProString &ProString::append(QChar other) |
199 | { |
200 | if (m_length != m_string.length()) { |
201 | m_string = toQStringView() + other; |
202 | m_offset = 0; |
203 | m_length = m_string.length(); |
204 | } else { |
205 | Q_ASSERT(m_offset == 0); |
206 | m_string.append(other); |
207 | ++m_length; |
208 | } |
209 | m_hash = 0x80000000; |
210 | return *this; |
211 | } |
212 | |
213 | // If pending != 0, prefix with space if appending to non-empty non-pending |
214 | ProString &ProString::append(const ProString &other, bool *pending) |
215 | { |
216 | if (other.m_length) { |
217 | if (!m_length) { |
218 | *this = other; |
219 | } else { |
220 | if (m_length != m_string.length()) |
221 | m_string = toQString(); |
222 | if (pending && !*pending) { |
223 | m_string += QLatin1Char(' ') + other.toQStringView(); |
224 | } else { |
225 | m_string += other.toQStringView(); |
226 | } |
227 | m_length = m_string.length(); |
228 | m_offset = 0; |
229 | if (other.m_file) |
230 | m_file = other.m_file; |
231 | m_hash = 0x80000000; |
232 | } |
233 | if (pending) |
234 | *pending = true; |
235 | } |
236 | return *this; |
237 | } |
238 | |
239 | ProString &ProString::append(const ProStringList &other, bool *pending, bool skipEmpty1st) |
240 | { |
241 | if (const int sz = other.size()) { |
242 | int startIdx = 0; |
243 | if (pending && !*pending && skipEmpty1st && other.at(0).isEmpty()) { |
244 | if (sz == 1) |
245 | return *this; |
246 | startIdx = 1; |
247 | } |
248 | if (!m_length && sz == startIdx + 1) { |
249 | *this = other.at(startIdx); |
250 | } else { |
251 | int totalLength = sz - startIdx; |
252 | for (int i = startIdx; i < sz; ++i) |
253 | totalLength += other.at(i).size(); |
254 | bool putSpace = false; |
255 | if (pending && !*pending && m_length) |
256 | putSpace = true; |
257 | else |
258 | totalLength--; |
259 | |
260 | m_string = toQString(); |
261 | m_offset = 0; |
262 | for (int i = startIdx; i < sz; ++i) { |
263 | if (putSpace) |
264 | m_string += QLatin1Char(' '); |
265 | else |
266 | putSpace = true; |
267 | const ProString &str = other.at(i); |
268 | m_string += str.toQStringView(); |
269 | } |
270 | m_length = m_string.length(); |
271 | if (other.last().m_file) |
272 | m_file = other.last().m_file; |
273 | m_hash = 0x80000000; |
274 | } |
275 | if (pending) |
276 | *pending = true; |
277 | } |
278 | return *this; |
279 | } |
280 | |
281 | QString operator+(const ProString &one, const ProString &two) |
282 | { |
283 | if (two.m_length) { |
284 | if (!one.m_length) { |
285 | return two.toQString(); |
286 | } else { |
287 | QString neu(one.m_length + two.m_length, Qt::Uninitialized); |
288 | ushort *ptr = (ushort *)neu.constData(); |
289 | memcpy(ptr, one.m_string.constData() + one.m_offset, one.m_length * 2); |
290 | memcpy(ptr + one.m_length, two.m_string.constData() + two.m_offset, two.m_length * 2); |
291 | return neu; |
292 | } |
293 | } |
294 | return one.toQString(); |
295 | } |
296 | |
297 | |
298 | ProString ProString::mid(int off, int len) const |
299 | { |
300 | ProString ret(*this, NoHash); |
301 | if (off > m_length) |
302 | off = m_length; |
303 | ret.m_offset += off; |
304 | ret.m_length -= off; |
305 | if ((uint)ret.m_length > (uint)len) // Unsigned comparison to interpret < 0 as infinite |
306 | ret.m_length = len; |
307 | return ret; |
308 | } |
309 | |
310 | ProString ProString::trimmed() const |
311 | { |
312 | ProString ret(*this, NoHash); |
313 | int cur = m_offset; |
314 | int end = cur + m_length; |
315 | const QChar *data = m_string.constData(); |
316 | for (; cur < end; cur++) |
317 | if (!data[cur].isSpace()) { |
318 | // No underrun check - we know there is at least one non-whitespace |
319 | while (data[end - 1].isSpace()) |
320 | end--; |
321 | break; |
322 | } |
323 | ret.m_offset = cur; |
324 | ret.m_length = end - cur; |
325 | return ret; |
326 | } |
327 | |
328 | QTextStream &operator<<(QTextStream &t, const ProString &str) |
329 | { |
330 | t << str.toQStringView(); |
331 | return t; |
332 | } |
333 | |
334 | static QString ProStringList_join(const ProStringList &this_, const QChar *sep, const int sepSize) |
335 | { |
336 | int totalLength = 0; |
337 | const int sz = this_.size(); |
338 | |
339 | for (int i = 0; i < sz; ++i) |
340 | totalLength += this_.at(i).size(); |
341 | |
342 | if (sz) |
343 | totalLength += sepSize * (sz - 1); |
344 | |
345 | QString res(totalLength, Qt::Uninitialized); |
346 | QChar *ptr = (QChar *)res.constData(); |
347 | for (int i = 0; i < sz; ++i) { |
348 | if (i) { |
349 | memcpy(ptr, sep, sepSize * sizeof(QChar)); |
350 | ptr += sepSize; |
351 | } |
352 | const ProString &str = this_.at(i); |
353 | memcpy(ptr, str.constData(), str.size() * sizeof(QChar)); |
354 | ptr += str.size(); |
355 | } |
356 | return res; |
357 | } |
358 | |
359 | QString ProStringList::join(const ProString &sep) const |
360 | { |
361 | return ProStringList_join(*this, sep.constData(), sep.size()); |
362 | } |
363 | |
364 | QString ProStringList::join(const QString &sep) const |
365 | { |
366 | return ProStringList_join(*this, sep.constData(), sep.size()); |
367 | } |
368 | |
369 | QString ProStringList::join(QChar sep) const |
370 | { |
371 | return ProStringList_join(*this, &sep, 1); |
372 | } |
373 | |
374 | void ProStringList::removeAll(const ProString &str) |
375 | { |
376 | for (int i = size(); --i >= 0; ) |
377 | if (at(i) == str) |
378 | remove(i); |
379 | } |
380 | |
381 | void ProStringList::removeAll(const char *str) |
382 | { |
383 | for (int i = size(); --i >= 0; ) |
384 | if (at(i) == str) |
385 | remove(i); |
386 | } |
387 | |
388 | void ProStringList::removeEach(const ProStringList &value) |
389 | { |
390 | for (const ProString &str : value) { |
391 | if (isEmpty()) |
392 | break; |
393 | if (!str.isEmpty()) |
394 | removeAll(str); |
395 | } |
396 | } |
397 | |
398 | void ProStringList::removeEmpty() |
399 | { |
400 | for (int i = size(); --i >= 0;) |
401 | if (at(i).isEmpty()) |
402 | remove(i); |
403 | } |
404 | |
405 | void ProStringList::removeDuplicates() |
406 | { |
407 | QDuplicateTracker<ProString> seen; |
408 | seen.reserve(size()); |
409 | removeIf([&](const ProString &s) { return seen.hasSeen(s); }); |
410 | } |
411 | |
412 | void ProStringList::insertUnique(const ProStringList &value) |
413 | { |
414 | for (const ProString &str : value) |
415 | if (!str.isEmpty() && !contains(str)) |
416 | append(str); |
417 | } |
418 | |
419 | ProStringList::ProStringList(const QStringList &list) |
420 | { |
421 | reserve(list.size()); |
422 | for (const QString &str : list) |
423 | *this << ProString(str); |
424 | } |
425 | |
426 | QStringList ProStringList::toQStringList() const |
427 | { |
428 | QStringList ret; |
429 | ret.reserve(size()); |
430 | for (const auto &e : *this) |
431 | ret.append(e.toQString()); |
432 | return ret; |
433 | } |
434 | |
435 | bool ProStringList::contains(const ProString &str, Qt::CaseSensitivity cs) const |
436 | { |
437 | for (int i = 0; i < size(); i++) |
438 | if (!at(i).compare(str, cs)) |
439 | return true; |
440 | return false; |
441 | } |
442 | |
443 | bool ProStringList::contains(QStringView str, Qt::CaseSensitivity cs) const |
444 | { |
445 | for (int i = 0; i < size(); i++) |
446 | if (!at(i).toQStringView().compare(str, cs)) |
447 | return true; |
448 | return false; |
449 | } |
450 | |
451 | bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const |
452 | { |
453 | for (int i = 0; i < size(); i++) |
454 | if (!at(i).compare(str, cs)) |
455 | return true; |
456 | return false; |
457 | } |
458 | |
459 | ProFile::ProFile(int id, const QString &fileName) |
460 | : m_refCount(1), |
461 | m_fileName(fileName), |
462 | m_id(id), |
463 | m_ok(true), |
464 | m_hostBuild(false) |
465 | { |
466 | if (!fileName.startsWith(QLatin1Char('('))) |
467 | m_directoryName = QFileInfo( // qmake sickness: canonicalize only the directory! |
468 | fileName.left(fileName.lastIndexOf(QLatin1Char('/')))).canonicalFilePath(); |
469 | } |
470 | |
471 | ProFile::~ProFile() |
472 | { |
473 | } |
474 | |
475 | ProString ProFile::getStr(const ushort *&tPtr) |
476 | { |
477 | uint len = *tPtr++; |
478 | ProString ret(items(), tPtr - tokPtr(), len); |
479 | ret.setSource(m_id); |
480 | tPtr += len; |
481 | return ret; |
482 | } |
483 | |
484 | ProKey ProFile::getHashStr(const ushort *&tPtr) |
485 | { |
486 | uint hash = *tPtr++; |
487 | hash |= (uint)*tPtr++ << 16; |
488 | uint len = *tPtr++; |
489 | ProKey ret(items(), tPtr - tokPtr(), len, hash); |
490 | tPtr += len; |
491 | return ret; |
492 | } |
493 | |
494 | QDebug operator<<(QDebug debug, const ProString &str) |
495 | { |
496 | return debug << str.toQString(); |
497 | } |
498 | |
499 | QT_END_NAMESPACE |
500 | |