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