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 | uint ProString::hash(const QChar *p, int n) |
40 | { |
41 | uint 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(const QStringRef &str) : |
78 | m_string(*str.string()), m_offset(str.position()), 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(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(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 | uint ProString::updatedHash() const |
115 | { |
116 | return (m_hash = hash(p: m_string.constData() + m_offset, n: m_length)); |
117 | } |
118 | |
119 | uint 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(position: m_offset, n: m_length); |
155 | } |
156 | |
157 | QString &ProString::toQString(QString &tmp) const |
158 | { |
159 | return tmp.setRawData(unicode: m_string.constData() + m_offset, size: m_length); |
160 | } |
161 | |
162 | /* |
163 | * \brief ProString::prepareExtend |
164 | * \param extraLen number of new characters to be added |
165 | * \param thisTarget offset to which current contents should be moved |
166 | * \param extraTarget offset at which new characters will be added |
167 | * \return pointer to storage location for new characters |
168 | * |
169 | * Prepares the string for adding new characters. |
170 | * If the string is detached and has enough space, it will be changed in place. |
171 | * Otherwise, it will be replaced with a new string object, thus detaching. |
172 | * In either case, the hash will be reset. |
173 | */ |
174 | QChar *ProString::prepareExtend(int , int thisTarget, int ) |
175 | { |
176 | if (m_string.isDetached() && m_length + extraLen <= m_string.capacity()) { |
177 | m_string.reserve(asize: 0); // Prevent the resize() below from reallocating |
178 | QChar *ptr = (QChar *)m_string.constData(); |
179 | if (m_offset != thisTarget) |
180 | memmove(dest: ptr + thisTarget, src: ptr + m_offset, n: m_length * 2); |
181 | ptr += extraTarget; |
182 | m_offset = 0; |
183 | m_length += extraLen; |
184 | m_string.resize(size: m_length); |
185 | m_hash = 0x80000000; |
186 | return ptr; |
187 | } else { |
188 | QString neu(m_length + extraLen, Qt::Uninitialized); |
189 | QChar *ptr = (QChar *)neu.constData(); |
190 | memcpy(dest: ptr + thisTarget, src: m_string.constData() + m_offset, n: m_length * 2); |
191 | ptr += extraTarget; |
192 | *this = ProString(neu); |
193 | return ptr; |
194 | } |
195 | } |
196 | |
197 | ProString &ProString::prepend(const ProString &other) |
198 | { |
199 | if (other.m_length) { |
200 | if (!m_length) { |
201 | *this = other; |
202 | } else { |
203 | QChar *ptr = prepareExtend(extraLen: other.m_length, thisTarget: other.m_length, extraTarget: 0); |
204 | memcpy(dest: ptr, src: other.constData(), n: other.m_length * 2); |
205 | if (!m_file) |
206 | m_file = other.m_file; |
207 | } |
208 | } |
209 | return *this; |
210 | } |
211 | |
212 | ProString &ProString::append(const QLatin1String other) |
213 | { |
214 | const char *latin1 = other.latin1(); |
215 | int size = other.size(); |
216 | if (size) { |
217 | QChar *ptr = prepareExtend(extraLen: size, thisTarget: 0, extraTarget: m_length); |
218 | for (int i = 0; i < size; i++) |
219 | *ptr++ = QLatin1Char(latin1[i]); |
220 | } |
221 | return *this; |
222 | } |
223 | |
224 | ProString &ProString::append(QChar other) |
225 | { |
226 | QChar *ptr = prepareExtend(extraLen: 1, thisTarget: 0, extraTarget: m_length); |
227 | *ptr = other; |
228 | return *this; |
229 | } |
230 | |
231 | // If pending != 0, prefix with space if appending to non-empty non-pending |
232 | ProString &ProString::append(const ProString &other, bool *pending) |
233 | { |
234 | if (other.m_length) { |
235 | if (!m_length) { |
236 | *this = other; |
237 | } else { |
238 | QChar *ptr; |
239 | if (pending && !*pending) { |
240 | ptr = prepareExtend(extraLen: 1 + other.m_length, thisTarget: 0, extraTarget: m_length); |
241 | *ptr++ = QLatin1Char(' '); |
242 | } else { |
243 | ptr = prepareExtend(extraLen: other.m_length, thisTarget: 0, extraTarget: m_length); |
244 | } |
245 | memcpy(dest: ptr, src: other.m_string.constData() + other.m_offset, n: other.m_length * 2); |
246 | if (other.m_file) |
247 | m_file = other.m_file; |
248 | } |
249 | if (pending) |
250 | *pending = true; |
251 | } |
252 | return *this; |
253 | } |
254 | |
255 | ProString &ProString::append(const ProStringList &other, bool *pending, bool skipEmpty1st) |
256 | { |
257 | if (const int sz = other.size()) { |
258 | int startIdx = 0; |
259 | if (pending && !*pending && skipEmpty1st && other.at(i: 0).isEmpty()) { |
260 | if (sz == 1) |
261 | return *this; |
262 | startIdx = 1; |
263 | } |
264 | if (!m_length && sz == startIdx + 1) { |
265 | *this = other.at(i: startIdx); |
266 | } else { |
267 | int totalLength = sz - startIdx; |
268 | for (int i = startIdx; i < sz; ++i) |
269 | totalLength += other.at(i).size(); |
270 | bool putSpace = false; |
271 | if (pending && !*pending && m_length) |
272 | putSpace = true; |
273 | else |
274 | totalLength--; |
275 | |
276 | QChar *ptr = prepareExtend(extraLen: totalLength, thisTarget: 0, extraTarget: m_length); |
277 | for (int i = startIdx; i < sz; ++i) { |
278 | if (putSpace) |
279 | *ptr++ = QLatin1Char(' '); |
280 | else |
281 | putSpace = true; |
282 | const ProString &str = other.at(i); |
283 | memcpy(dest: ptr, src: str.m_string.constData() + str.m_offset, n: str.m_length * 2); |
284 | ptr += str.m_length; |
285 | } |
286 | if (other.last().m_file) |
287 | m_file = other.last().m_file; |
288 | } |
289 | if (pending) |
290 | *pending = true; |
291 | } |
292 | return *this; |
293 | } |
294 | |
295 | QString operator+(const ProString &one, const ProString &two) |
296 | { |
297 | if (two.m_length) { |
298 | if (!one.m_length) { |
299 | return two.toQString(); |
300 | } else { |
301 | QString neu(one.m_length + two.m_length, Qt::Uninitialized); |
302 | ushort *ptr = (ushort *)neu.constData(); |
303 | memcpy(dest: ptr, src: one.m_string.constData() + one.m_offset, n: one.m_length * 2); |
304 | memcpy(dest: ptr + one.m_length, src: two.m_string.constData() + two.m_offset, n: two.m_length * 2); |
305 | return neu; |
306 | } |
307 | } |
308 | return one.toQString(); |
309 | } |
310 | |
311 | |
312 | ProString ProString::mid(int off, int len) const |
313 | { |
314 | ProString ret(*this, NoHash); |
315 | if (off > m_length) |
316 | off = m_length; |
317 | ret.m_offset += off; |
318 | ret.m_length -= off; |
319 | if ((uint)ret.m_length > (uint)len) // Unsigned comparison to interpret < 0 as infinite |
320 | ret.m_length = len; |
321 | return ret; |
322 | } |
323 | |
324 | ProString ProString::trimmed() const |
325 | { |
326 | ProString ret(*this, NoHash); |
327 | int cur = m_offset; |
328 | int end = cur + m_length; |
329 | const QChar *data = m_string.constData(); |
330 | for (; cur < end; cur++) |
331 | if (!data[cur].isSpace()) { |
332 | // No underrun check - we know there is at least one non-whitespace |
333 | while (data[end - 1].isSpace()) |
334 | end--; |
335 | break; |
336 | } |
337 | ret.m_offset = cur; |
338 | ret.m_length = end - cur; |
339 | return ret; |
340 | } |
341 | |
342 | QTextStream &operator<<(QTextStream &t, const ProString &str) |
343 | { |
344 | t << str.toQStringRef(); |
345 | return t; |
346 | } |
347 | |
348 | static QString ProStringList_join(const ProStringList &this_, const QChar *sep, const int sepSize) |
349 | { |
350 | int totalLength = 0; |
351 | const int sz = this_.size(); |
352 | |
353 | for (int i = 0; i < sz; ++i) |
354 | totalLength += this_.at(i).size(); |
355 | |
356 | if (sz) |
357 | totalLength += sepSize * (sz - 1); |
358 | |
359 | QString res(totalLength, Qt::Uninitialized); |
360 | QChar *ptr = (QChar *)res.constData(); |
361 | for (int i = 0; i < sz; ++i) { |
362 | if (i) { |
363 | memcpy(dest: ptr, src: sep, n: sepSize * sizeof(QChar)); |
364 | ptr += sepSize; |
365 | } |
366 | const ProString &str = this_.at(i); |
367 | memcpy(dest: ptr, src: str.constData(), n: str.size() * sizeof(QChar)); |
368 | ptr += str.size(); |
369 | } |
370 | return res; |
371 | } |
372 | |
373 | QString ProStringList::join(const ProString &sep) const |
374 | { |
375 | return ProStringList_join(this_: *this, sep: sep.constData(), sepSize: sep.size()); |
376 | } |
377 | |
378 | QString ProStringList::join(const QString &sep) const |
379 | { |
380 | return ProStringList_join(this_: *this, sep: sep.constData(), sepSize: sep.size()); |
381 | } |
382 | |
383 | QString ProStringList::join(QChar sep) const |
384 | { |
385 | return ProStringList_join(this_: *this, sep: &sep, sepSize: 1); |
386 | } |
387 | |
388 | void ProStringList::removeAll(const ProString &str) |
389 | { |
390 | for (int i = size(); --i >= 0; ) |
391 | if (at(i) == str) |
392 | remove(i); |
393 | } |
394 | |
395 | void ProStringList::removeAll(const char *str) |
396 | { |
397 | for (int i = size(); --i >= 0; ) |
398 | if (at(i) == str) |
399 | remove(i); |
400 | } |
401 | |
402 | void ProStringList::removeEach(const ProStringList &value) |
403 | { |
404 | for (const ProString &str : value) { |
405 | if (isEmpty()) |
406 | break; |
407 | if (!str.isEmpty()) |
408 | removeAll(str); |
409 | } |
410 | } |
411 | |
412 | void ProStringList::removeEmpty() |
413 | { |
414 | for (int i = size(); --i >= 0;) |
415 | if (at(i).isEmpty()) |
416 | remove(i); |
417 | } |
418 | |
419 | void ProStringList::removeDuplicates() |
420 | { |
421 | int n = size(); |
422 | int j = 0; |
423 | QSet<ProString> seen; |
424 | seen.reserve(asize: n); |
425 | for (int i = 0; i < n; ++i) { |
426 | const ProString &s = at(i); |
427 | if (seen.contains(value: s)) |
428 | continue; |
429 | seen.insert(value: s); |
430 | if (j != i) |
431 | (*this)[j] = s; |
432 | ++j; |
433 | } |
434 | if (n != j) |
435 | erase(abegin: begin() + j, aend: end()); |
436 | } |
437 | |
438 | void ProStringList::insertUnique(const ProStringList &value) |
439 | { |
440 | for (const ProString &str : value) |
441 | if (!str.isEmpty() && !contains(str)) |
442 | append(t: str); |
443 | } |
444 | |
445 | ProStringList::ProStringList(const QStringList &list) |
446 | { |
447 | reserve(asize: list.size()); |
448 | for (const QString &str : list) |
449 | *this << ProString(str); |
450 | } |
451 | |
452 | QStringList ProStringList::toQStringList() const |
453 | { |
454 | QStringList ret; |
455 | ret.reserve(alloc: size()); |
456 | for (const auto &e : *this) |
457 | ret.append(t: e.toQString()); |
458 | return ret; |
459 | } |
460 | |
461 | bool ProStringList::contains(const ProString &str, Qt::CaseSensitivity cs) const |
462 | { |
463 | for (int i = 0; i < size(); i++) |
464 | if (!at(i).compare(sub: str, cs)) |
465 | return true; |
466 | return false; |
467 | } |
468 | |
469 | bool ProStringList::contains(const QStringRef &str, Qt::CaseSensitivity cs) const |
470 | { |
471 | for (int i = 0; i < size(); i++) |
472 | if (!at(i).toQStringRef().compare(s: str, cs)) |
473 | return true; |
474 | return false; |
475 | } |
476 | |
477 | bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const |
478 | { |
479 | for (int i = 0; i < size(); i++) |
480 | if (!at(i).compare(sub: str, cs)) |
481 | return true; |
482 | return false; |
483 | } |
484 | |
485 | ProFile::ProFile(int id, const QString &fileName) |
486 | : m_refCount(1), |
487 | m_fileName(fileName), |
488 | m_id(id), |
489 | m_ok(true), |
490 | m_hostBuild(false) |
491 | { |
492 | if (!fileName.startsWith(c: QLatin1Char('('))) |
493 | m_directoryName = QFileInfo( // qmake sickness: canonicalize only the directory! |
494 | fileName.left(n: fileName.lastIndexOf(c: QLatin1Char('/')))).canonicalFilePath(); |
495 | } |
496 | |
497 | ProFile::~ProFile() |
498 | { |
499 | } |
500 | |
501 | ProString ProFile::getStr(const ushort *&tPtr) |
502 | { |
503 | uint len = *tPtr++; |
504 | ProString ret(items(), tPtr - tokPtr(), len); |
505 | ret.setSource(m_id); |
506 | tPtr += len; |
507 | return ret; |
508 | } |
509 | |
510 | ProKey ProFile::getHashStr(const ushort *&tPtr) |
511 | { |
512 | uint hash = *tPtr++; |
513 | hash |= (uint)*tPtr++ << 16; |
514 | uint len = *tPtr++; |
515 | ProKey ret(items(), tPtr - tokPtr(), len, hash); |
516 | tPtr += len; |
517 | return ret; |
518 | } |
519 | |
520 | QDebug operator<<(QDebug debug, const ProString &str) |
521 | { |
522 | return debug << str.toQString(); |
523 | } |
524 | |
525 | QT_END_NAMESPACE |
526 | |