Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the qmake application of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "makefiledeps.h"
43#include "option.h"
44#include <qdir.h>
45#include <qdatetime.h>
46#include <qfileinfo.h>
47#include <qbuffer.h>
48#include <qplatformdefs.h>
49#if defined(Q_OS_UNIX)
50# include <unistd.h>
51#else
52# include <io.h>
53#endif
54#include <qdebug.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <time.h>
58#include <fcntl.h>
59#include <sys/types.h>
60#include <sys/stat.h>
61#if defined(_MSC_VER) && _MSC_VER >= 1400
62#include <share.h>
63#endif
64
65QT_BEGIN_NAMESPACE
66
67#if 1
68#define qmake_endOfLine(c) (c == '\r' || c == '\n')
69#else
70inline bool qmake_endOfLine(const char &c) { return (c == '\r' || c == '\n'); }
71#endif
72
73//#define QMAKE_USE_CACHE
74
75QMakeLocalFileName::QMakeLocalFileName(const QString &name) : is_null(name.isNull())
76{
77 if(!name.isEmpty()) {
78 if(name.at(0) == QLatin1Char('"') && name.at(name.length()-2) == QLatin1Char('"'))
79 real_name = name.mid(1, name.length()-2);
80 else
81 real_name = name;
82 }
83}
84const QString
85&QMakeLocalFileName::local() const
86{
87 if(!is_null && local_name.isNull())
88 local_name = Option::fixPathToLocalOS(real_name, true);
89 return local_name;
90}
91
92struct SourceDependChildren;
93struct SourceFile {
94 SourceFile() : deps(0), type(QMakeSourceFileInfo::TYPE_UNKNOWN),
95 mocable(0), traversed(0), exists(1),
96 moc_checked(0), dep_checked(0), included_count(0) { }
97 ~SourceFile();
98 QMakeLocalFileName file;
99 SourceDependChildren *deps;
100 QMakeSourceFileInfo::SourceFileType type;
101 uint mocable : 1, traversed : 1, exists : 1;
102 uint moc_checked : 1, dep_checked : 1;
103 uchar included_count;
104};
105struct SourceDependChildren {
106 SourceFile **children;
107 int num_nodes, used_nodes;
108 SourceDependChildren() : children(0), num_nodes(0), used_nodes(0) { }
109 ~SourceDependChildren() { if(children) free(children); children = 0; }
110 void addChild(SourceFile *s) {
111 if(num_nodes <= used_nodes) {
112 num_nodes += 200;
113 children = (SourceFile**)realloc(children, sizeof(SourceFile*)*(num_nodes));
114 }
115 children[used_nodes++] = s;
116 }
117};
118SourceFile::~SourceFile() { delete deps; }
119class SourceFiles {
120 int hash(const char *);
121public:
122 SourceFiles();
123 ~SourceFiles();
124
125 SourceFile *lookupFile(const char *);
126 inline SourceFile *lookupFile(const QString &f) { return lookupFile(f.toLatin1().constData()); }
127 inline SourceFile *lookupFile(const QMakeLocalFileName &f) { return lookupFile(f.local().toLatin1().constData()); }
128 void addFile(SourceFile *, const char *k=0, bool own=true);
129
130 struct SourceFileNode {
131 SourceFileNode() : key(0), next(0), file(0), own_file(1) { }
132 ~SourceFileNode() {
133 delete [] key;
134 if(own_file)
135 delete file;
136 }
137 char *key;
138 SourceFileNode *next;
139 SourceFile *file;
140 uint own_file : 1;
141 } **nodes;
142 int num_nodes;
143};
144SourceFiles::SourceFiles()
145{
146 nodes = (SourceFileNode**)malloc(sizeof(SourceFileNode*)*(num_nodes=3037));
147 for(int n = 0; n < num_nodes; n++)
148 nodes[n] = 0;
149}
150
151SourceFiles::~SourceFiles()
152{
153 for(int n = 0; n < num_nodes; n++) {
154 for(SourceFileNode *next = nodes[n]; next;) {
155 SourceFileNode *next_next = next->next;
156 delete next;
157 next = next_next;
158 }
159 }
160 free(nodes);
161}
162
163int SourceFiles::hash(const char *file)
164{
165 uint h = 0, g;
166 while (*file) {
167 h = (h << 4) + *file;
168 if ((g = (h & 0xf0000000)) != 0)
169 h ^= g >> 23;
170 h &= ~g;
171 file++;
172 }
173 return h;
174}
175
176SourceFile *SourceFiles::lookupFile(const char *file)
177{
178 int h = hash(file) % num_nodes;
179 for(SourceFileNode *p = nodes[h]; p; p = p->next) {
180 if(!strcmp(p->key, file))
181 return p->file;
182 }
183 return 0;
184}
185
186void SourceFiles::addFile(SourceFile *p, const char *k, bool own_file)
187{
188 QByteArray ba = p->file.local().toLatin1();
189 if(!k)
190 k = ba;
191 int h = hash(k) % num_nodes;
192 SourceFileNode *pn = new SourceFileNode;
193 pn->own_file = own_file;
194 pn->key = qstrdup(k);
195 pn->file = p;
196 pn->next = nodes[h];
197 nodes[h] = pn;
198}
199
200void QMakeSourceFileInfo::dependTreeWalker(SourceFile *node, SourceDependChildren *place)
201{
202 if(node->traversed || !node->exists)
203 return;
204 place->addChild(node);
205 node->traversed = true; //set flag
206 if(node->deps) {
207 for(int i = 0; i < node->deps->used_nodes; i++)
208 dependTreeWalker(node->deps->children[i], place);
209 }
210}
211
212void QMakeSourceFileInfo::setDependencyPaths(const QList<QMakeLocalFileName> &l)
213{
214 // Ensure that depdirs does not contain the same paths several times, to minimize the stats
215 QList<QMakeLocalFileName> ll;
216 for (int i = 0; i < l.count(); ++i) {
217 if (!ll.contains(l.at(i)))
218 ll.append(l.at(i));
219 }
220 depdirs = ll;
221}
222
223QStringList QMakeSourceFileInfo::dependencies(const QString &file)
224{
225 QStringList ret;
226 if(!files)
227 return ret;
228
229 if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file))) {
230 if(node->deps) {
231 /* I stick them into a SourceDependChildren here because it is faster to just
232 iterate over the list to stick them in the list, and reset the flag, then it is
233 to loop over the tree (about 50% faster I saw) --Sam */
234 SourceDependChildren place;
235 for(int i = 0; i < node->deps->used_nodes; i++)
236 dependTreeWalker(node->deps->children[i], &place);
237 if(place.children) {
238 for(int i = 0; i < place.used_nodes; i++) {
239 place.children[i]->traversed = false; //reset flag
240 ret.append(place.children[i]->file.real());
241 }
242 }
243 }
244 }
245 return ret;
246}
247
248int
249QMakeSourceFileInfo::included(const QString &file)
250{
251 if (!files)
252 return 0;
253
254 if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file)))
255 return node->included_count;
256 return 0;
257}
258
259bool QMakeSourceFileInfo::mocable(const QString &file)
260{
261 if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file)))
262 return node->mocable;
263 return false;
264}
265
266QMakeSourceFileInfo::QMakeSourceFileInfo(const QString &cf)
267{
268 //dep_mode
269 dep_mode = Recursive;
270
271 //quick project lookups
272 includes = files = 0;
273 files_changed = false;
274
275 //buffer
276 spare_buffer = 0;
277 spare_buffer_size = 0;
278
279 //cache
280 cachefile = cf;
281 if(!cachefile.isEmpty())
282 loadCache(cachefile);
283}
284
285QMakeSourceFileInfo::~QMakeSourceFileInfo()
286{
287 //cache
288 if(!cachefile.isEmpty() /*&& files_changed*/)
289 saveCache(cachefile);
290
291 //buffer
292 if(spare_buffer) {
293 free(spare_buffer);
294 spare_buffer = 0;
295 spare_buffer_size = 0;
296 }
297
298 //quick project lookup
299 delete files;
300 delete includes;
301}
302
303void QMakeSourceFileInfo::setCacheFile(const QString &cf)
304{
305 cachefile = cf;
306 loadCache(cachefile);
307}
308
309void QMakeSourceFileInfo::addSourceFiles(const QStringList &l, uchar seek,
310 QMakeSourceFileInfo::SourceFileType type)
311{
312 for(int i=0; i<l.size(); ++i)
313 addSourceFile(l.at(i), seek, type);
314}
315void QMakeSourceFileInfo::addSourceFile(const QString &f, uchar seek,
316 QMakeSourceFileInfo::SourceFileType type)
317{
318 if(!files)
319 files = new SourceFiles;
320
321 QMakeLocalFileName fn(f);
322 SourceFile *file = files->lookupFile(fn);
323 if(!file) {
324 file = new SourceFile;
325 file->file = fn;
326 files->addFile(file);
327 } else {
328 if(file->type != type && file->type != TYPE_UNKNOWN && type != TYPE_UNKNOWN)
329 warn_msg(WarnLogic, "%s is marked as %d, then %d!", f.toLatin1().constData(),
330 file->type, type);
331 }
332 if(type != TYPE_UNKNOWN)
333 file->type = type;
334
335 if(seek & SEEK_MOCS && !file->moc_checked)
336 findMocs(file);
337 if(seek & SEEK_DEPS && !file->dep_checked)
338 findDeps(file);
339}
340
341bool QMakeSourceFileInfo::containsSourceFile(const QString &f, SourceFileType type)
342{
343 if(SourceFile *file = files->lookupFile(QMakeLocalFileName(f)))
344 return (file->type == type || file->type == TYPE_UNKNOWN || type == TYPE_UNKNOWN);
345 return false;
346}
347
348char *QMakeSourceFileInfo::getBuffer(int s) {
349 if(!spare_buffer || spare_buffer_size < s)
350 spare_buffer = (char *)realloc(spare_buffer, spare_buffer_size=s);
351 return spare_buffer;
352}
353
354#ifndef S_ISDIR
355#define S_ISDIR(x) (x & _S_IFDIR)
356#endif
357
358QMakeLocalFileName QMakeSourceFileInfo::fixPathForFile(const QMakeLocalFileName &f, bool)
359{
360 return f;
361}
362
363QMakeLocalFileName QMakeSourceFileInfo::findFileForDep(const QMakeLocalFileName &/*dep*/,
364 const QMakeLocalFileName &/*file*/)
365{
366 return QMakeLocalFileName();
367}
368
369QFileInfo QMakeSourceFileInfo::findFileInfo(const QMakeLocalFileName &dep)
370{
371 return QFileInfo(dep.real());
372}
373
374bool QMakeSourceFileInfo::findDeps(SourceFile *file)
375{
376 if(file->dep_checked || file->type == TYPE_UNKNOWN)
377 return true;
378 files_changed = true;
379 file->dep_checked = true;
380
381 const QMakeLocalFileName sourceFile = fixPathForFile(file->file, true);
382
383 struct stat fst;
384 char *buffer = 0;
385 int buffer_len = 0;
386 {
387 int fd;
388#if defined(_MSC_VER) && _MSC_VER >= 1400
389 if (_sopen_s(&fd, sourceFile.local().toLatin1().constData(),
390 _O_RDONLY, _SH_DENYNO, _S_IREAD) != 0)
391 fd = -1;
392#else
393 fd = open(sourceFile.local().toLatin1().constData(), O_RDONLY);
394#endif
395 if(fd == -1 || fstat(fd, &fst) || S_ISDIR(fst.st_mode))
396 return false;
397 buffer = getBuffer(fst.st_size);
398 for(int have_read = 0;
399 (have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len));
400 buffer_len += have_read) ;
401 QT_CLOSE(fd);
402 }
403 if(!buffer)
404 return false;
405 if(!file->deps)
406 file->deps = new SourceDependChildren;
407
408 int line_count = 1;
409
410 for(int x = 0; x < buffer_len; ++x) {
411 bool try_local = true;
412 char *inc = 0;
413 if(file->type == QMakeSourceFileInfo::TYPE_UI) {
414 // skip whitespaces
415 while(x < buffer_len && (*(buffer+x) == ' ' || *(buffer+x) == '\t'))
416 ++x;
417 if(*(buffer + x) == '<') {
418 ++x;
419 if(buffer_len >= x + 12 && !strncmp(buffer + x, "includehint", 11) &&
420 (*(buffer + x + 11) == ' ' || *(buffer + x + 11) == '>')) {
421 for(x += 11; *(buffer + x) != '>'; ++x) ;
422 int inc_len = 0;
423 for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len) ;
424 *(buffer + x + inc_len) = '\0';
425 inc = buffer + x;
426 } else if(buffer_len >= x + 13 && !strncmp(buffer + x, "customwidget", 12) &&
427 (*(buffer + x + 12) == ' ' || *(buffer + x + 12) == '>')) {
428 for(x += 13; *(buffer + x) != '>'; ++x) ; //skip up to >
429 while(x < buffer_len) {
430 for(x++; *(buffer + x) != '<'; ++x) ; //skip up to <
431 x++;
432 if(buffer_len >= x + 7 && !strncmp(buffer+x, "header", 6) &&
433 (*(buffer + x + 6) == ' ' || *(buffer + x + 6) == '>')) {
434 for(x += 7; *(buffer + x) != '>'; ++x) ; //skip up to >
435 int inc_len = 0;
436 for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len) ;
437 *(buffer + x + inc_len) = '\0';
438 inc = buffer + x;
439 break;
440 } else if(buffer_len >= x + 14 && !strncmp(buffer+x, "/customwidget", 13) &&
441 (*(buffer + x + 13) == ' ' || *(buffer + x + 13) == '>')) {
442 x += 14;
443 break;
444 }
445 }
446 } else if(buffer_len >= x + 8 && !strncmp(buffer + x, "include", 7) &&
447 (*(buffer + x + 7) == ' ' || *(buffer + x + 7) == '>')) {
448 for(x += 8; *(buffer + x) != '>'; ++x) {
449 if(buffer_len >= x + 9 && *(buffer + x) == 'i' &&
450 !strncmp(buffer + x, "impldecl", 8)) {
451 for(x += 8; *(buffer + x) != '='; ++x) ;
452 if(*(buffer + x) != '=')
453 continue;
454 for(++x; *(buffer+x) == '\t' || *(buffer+x) == ' '; ++x) ;
455 char quote = 0;
456 if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
457 quote = *(buffer + x);
458 ++x;
459 }
460 int val_len;
461 for(val_len = 0; true; ++val_len) {
462 if(quote) {
463 if(*(buffer+x+val_len) == quote)
464 break;
465 } else if(*(buffer + x + val_len) == '>' ||
466 *(buffer + x + val_len) == ' ') {
467 break;
468 }
469 }
470//? char saved = *(buffer + x + val_len);
471 *(buffer + x + val_len) = '\0';
472 if(!strcmp(buffer+x, "in implementation")) {
473 //### do this
474 }
475 }
476 }
477 int inc_len = 0;
478 for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len) ;
479 *(buffer + x + inc_len) = '\0';
480 inc = buffer + x;
481 }
482 }
483 //read past new line now..
484 for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ;
485 ++line_count;
486 } else if(file->type == QMakeSourceFileInfo::TYPE_QRC) {
487 } else if(file->type == QMakeSourceFileInfo::TYPE_C) {
488 for(int beginning=1; x < buffer_len; ++x) {
489 // whitespace comments and line-endings
490 for(; x < buffer_len; ++x) {
491 if(*(buffer+x) == ' ' || *(buffer+x) == '\t') {
492 // keep going
493 } else if(*(buffer+x) == '/') {
494 ++x;
495 if(buffer_len >= x) {
496 if(*(buffer+x) == '/') { //c++ style comment
497 for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ;
498 beginning = 1;
499 } else if(*(buffer+x) == '*') { //c style comment
500 for(++x; x < buffer_len; ++x) {
501 if(*(buffer+x) == '*') {
502 if(x+1 < buffer_len && *(buffer + (x+1)) == '/') {
503 ++x;
504 break;
505 }
506 } else if(qmake_endOfLine(*(buffer+x))) {
507 ++line_count;
508 }
509 }
510 }
511 }
512 } else if(qmake_endOfLine(*(buffer+x))) {
513 ++line_count;
514 beginning = 1;
515 } else {
516 break;
517 }
518 }
519
520 if(x >= buffer_len)
521 break;
522
523 // preprocessor directive
524 if(beginning && *(buffer+x) == '#')
525 break;
526
527 // quoted strings
528 if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
529 const char term = *(buffer+(x++));
530 for(; x < buffer_len; ++x) {
531 if(*(buffer+x) == term) {
532 ++x;
533 break;
534 } else if(*(buffer+x) == '\\') {
535 ++x;
536 } else if(qmake_endOfLine(*(buffer+x))) {
537 ++line_count;
538 }
539 }
540 }
541 beginning = 0;
542 }
543 if(x >= buffer_len)
544 break;
545
546 //got a preprocessor symbol
547 ++x;
548 while(x < buffer_len) {
549 if(*(buffer+x) != ' ' && *(buffer+x) != '\t')
550 break;
551 ++x;
552 }
553
554 int keyword_len = 0;
555 const char *keyword = buffer+x;
556 while(x+keyword_len < buffer_len) {
557 if(((*(buffer+x+keyword_len) < 'a' || *(buffer+x+keyword_len) > 'z')) &&
558 *(buffer+x+keyword_len) != '_') {
559 for(x+=keyword_len; //skip spaces after keyword
560 x < buffer_len && (*(buffer+x) == ' ' || *(buffer+x) == '\t');
561 x++) ;
562 break;
563 } else if(qmake_endOfLine(*(buffer+x+keyword_len))) {
564 x += keyword_len-1;
565 keyword_len = 0;
566 break;
567 }
568 keyword_len++;
569 }
570
571 if((keyword_len == 7 && !strncmp(keyword, "include", 7)) // C & Obj-C
572 || (keyword_len == 6 && !strncmp(keyword, "import", 6))) { // Obj-C
573 char term = *(buffer + x);
574 if(term == '<') {
575 try_local = false;
576 term = '>';
577 } else if(term != '"') { //wtf?
578 continue;
579 }
580 x++;
581
582 int inc_len;
583 for(inc_len = 0; *(buffer + x + inc_len) != term && !qmake_endOfLine(*(buffer + x + inc_len)); ++inc_len) ;
584 *(buffer + x + inc_len) = '\0';
585 inc = buffer + x;
586 x += inc_len;
587 } else if(keyword_len == 13 && !strncmp(keyword, "qmake_warning", keyword_len)) {
588 char term = 0;
589 if(*(buffer + x) == '"')
590 term = '"';
591 if(*(buffer + x) == '\'')
592 term = '\'';
593 if(term)
594 x++;
595
596 int msg_len;
597 for(msg_len = 0; (term && *(buffer + x + msg_len) != term) &&
598 !qmake_endOfLine(*(buffer + x + msg_len)); ++msg_len) ;
599 *(buffer + x + msg_len) = '\0';
600 debug_msg(0, "%s:%d %s -- %s", file->file.local().toLatin1().constData(), line_count, keyword, buffer+x);
601 x += msg_len;
602 } else if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
603 const char term = *(buffer+(x++));
604 while(x < buffer_len) {
605 if(*(buffer+x) == term)
606 break;
607 if(*(buffer+x) == '\\') {
608 x+=2;
609 } else {
610 if(qmake_endOfLine(*(buffer+x)))
611 ++line_count;
612 ++x;
613 }
614 }
615 } else {
616 --x;
617 }
618 }
619
620 if(inc) {
621 if(!includes)
622 includes = new SourceFiles;
623 SourceFile *dep = includes->lookupFile(inc);
624 if(!dep) {
625 bool exists = false;
626 QMakeLocalFileName lfn(inc);
627 if(QDir::isRelativePath(lfn.real())) {
628 if(try_local) {
629 QDir sourceDir = findFileInfo(sourceFile).dir();
630 QMakeLocalFileName f(sourceDir.absoluteFilePath(lfn.local()));
631 if(findFileInfo(f).exists()) {
632 lfn = fixPathForFile(f);
633 exists = true;
634 }
635 }
636 if(!exists) { //path lookup
637 for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin(); it != depdirs.end(); ++it) {
638 QMakeLocalFileName f((*it).real() + Option::dir_sep + lfn.real());
639 QFileInfo fi(findFileInfo(f));
640 if(fi.exists() && !fi.isDir()) {
641 lfn = fixPathForFile(f);
642 exists = true;
643 break;
644 }
645 }
646 }
647 if(!exists) { //heuristic lookup
648 lfn = findFileForDep(QMakeLocalFileName(inc), file->file);
649 if((exists = !lfn.isNull()))
650 lfn = fixPathForFile(lfn);
651 }
652 } else {
653 exists = QFile::exists(lfn.real());
654 }
655 if(!lfn.isNull()) {
656 dep = files->lookupFile(lfn);
657 if(!dep) {
658 dep = new SourceFile;
659 dep->file = lfn;
660 dep->type = QMakeSourceFileInfo::TYPE_C;
661 files->addFile(dep);
662 includes->addFile(dep, inc, false);
663 }
664 dep->exists = exists;
665 }
666 }
667 if(dep && dep->file != file->file) {
668 dep->included_count++;
669 if(dep->exists) {
670 debug_msg(5, "%s:%d Found dependency to %s", file->file.real().toLatin1().constData(),
671 line_count, dep->file.local().toLatin1().constData());
672 file->deps->addChild(dep);
673 }
674 }
675 }
676 }
677 if(dependencyMode() == Recursive) { //done last because buffer is shared
678 for(int i = 0; i < file->deps->used_nodes; i++) {
679 if(!file->deps->children[i]->deps)
680 findDeps(file->deps->children[i]);
681 }
682 }
683 return true;
684}
685
686bool QMakeSourceFileInfo::findMocs(SourceFile *file)
687{
688 if(file->moc_checked)
689 return true;
690 files_changed = true;
691 file->moc_checked = true;
692
693 int buffer_len;
694 char *buffer = 0;
695 {
696 struct stat fst;
697 int fd;
698#if defined(_MSC_VER) && _MSC_VER >= 1400
699 if (_sopen_s(&fd, fixPathForFile(file->file, true).local().toLocal8Bit().constData(),
700 _O_RDONLY, _SH_DENYNO, _S_IREAD) != 0)
701 fd = -1;
702#else
703 fd = open(fixPathForFile(file->file, true).local().toLocal8Bit().constData(), O_RDONLY);
704#endif
705 if(fd == -1 || fstat(fd, &fst) || S_ISDIR(fst.st_mode))
706 return false; //shouldn't happen
707 buffer = getBuffer(fst.st_size);
708 for(int have_read = buffer_len = 0;
709 (have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len));
710 buffer_len += have_read) ;
711 QT_CLOSE(fd);
712 }
713
714 debug_msg(2, "findMocs: %s", file->file.local().toLatin1().constData());
715 int line_count = 1;
716 bool ignore_qobject = false, ignore_qgadget = false;
717 /* qmake ignore Q_GADGET */
718 /* qmake ignore Q_OBJECT */
719 for(int x = 0; x < buffer_len; x++) {
720 if(*(buffer + x) == '/') {
721 ++x;
722 if(buffer_len >= x) {
723 if(*(buffer + x) == '/') { //c++ style comment
724 for(;x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ;
725 } else if(*(buffer + x) == '*') { //c style comment
726 for(++x; x < buffer_len; ++x) {
727 if(*(buffer + x) == 't' || *(buffer + x) == 'q') { //ignore
728 if(buffer_len >= (x + 20) &&
729 !strncmp(buffer + x + 1, "make ignore Q_OBJECT", 20)) {
730 debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_OBJECT\"",
731 file->file.real().toLatin1().constData(), line_count);
732 x += 20;
733 ignore_qobject = true;
734 } else if(buffer_len >= (x + 20) &&
735 !strncmp(buffer + x + 1, "make ignore Q_GADGET", 20)) {
736 debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_GADGET\"",
737 file->file.real().toLatin1().constData(), line_count);
738 x += 20;
739 ignore_qgadget = true;
740 }
741 } else if(*(buffer + x) == '*') {
742 if(buffer_len >= (x+1) && *(buffer + (x+1)) == '/') {
743 ++x;
744 break;
745 }
746 } else if(Option::debug_level && qmake_endOfLine(*(buffer + x))) {
747 ++line_count;
748 }
749 }
750 }
751 }
752 } else if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
753 const char term = *(buffer+(x++));
754 while(x < buffer_len) {
755 if(*(buffer+x) == term)
756 break;
757 if(*(buffer+x) == '\\') {
758 x+=2;
759 } else {
760 if(qmake_endOfLine(*(buffer+x)))
761 ++line_count;
762 ++x;
763 }
764 }
765 }
766 if(Option::debug_level && qmake_endOfLine(*(buffer+x)))
767 ++line_count;
768 if(((buffer_len > x+2 && *(buffer+x+1) == 'Q' && *(buffer+x+2) == '_')
769 ||
770 (buffer_len > x+4 && *(buffer+x+1) == 'Q' && *(buffer+x+2) == 'O'
771 && *(buffer+x+3) == 'M' && *(buffer+x+4) == '_'))
772 &&
773 *(buffer + x) != '_' &&
774 (*(buffer + x) < 'a' || *(buffer + x) > 'z') &&
775 (*(buffer + x) < 'A' || *(buffer + x) > 'Z') &&
776 (*(buffer + x) < '0' || *(buffer + x) > '9')) {
777 ++x;
778 int match = 0;
779 static const char *interesting[] = { "OBJECT", "GADGET",
780 "M_OBJECT" };
781 for(int interest = 0, m1, m2; interest < 3; ++interest) {
782 if(interest == 0 && ignore_qobject)
783 continue;
784 else if(interest == 1 && ignore_qgadget)
785 continue;
786 for(m1 = 0, m2 = 0; *(interesting[interest]+m1); ++m1) {
787 if(*(interesting[interest]+m1) != *(buffer+x+2+m1)) {
788 m2 = -1;
789 break;
790 }
791 ++m2;
792 }
793 if(m1 == m2) {
794 match = m2 + 2;
795 break;
796 }
797 }
798 if(match && *(buffer+x+match) != '_' &&
799 (*(buffer+x+match) < 'a' || *(buffer+x+match) > 'z') &&
800 (*(buffer+x+match) < 'A' || *(buffer+x+match) > 'Z') &&
801 (*(buffer+x+match) < '0' || *(buffer+x+match) > '9')) {
802 if(Option::debug_level) {
803 *(buffer+x+match) = '\0';
804 debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", file->file.real().toLatin1().constData(),
805 line_count, buffer+x);
806 }
807 file->mocable = true;
808 return true;
809 }
810 }
811 }
812 return true;
813}
814
815
816void QMakeSourceFileInfo::saveCache(const QString &cf)
817{
818#ifdef QMAKE_USE_CACHE
819 if(cf.isEmpty())
820 return;
821
822 QFile file(QMakeLocalFileName(cf).local());
823 if(file.open(QIODevice::WriteOnly)) {
824 QTextStream stream(&file);
825 stream << qmake_version() << endl << endl; //version
826 { //cache verification
827 QMap<QString, QStringList> verify = getCacheVerification();
828 stream << verify.count() << endl;
829 for(QMap<QString, QStringList>::iterator it = verify.begin();
830 it != verify.end(); ++it) {
831 stream << it.key() << endl << it.value().join(";") << endl;
832 }
833 stream << endl;
834 }
835 if(files->nodes) {
836 for(int file = 0; file < files->num_nodes; ++file) {
837 for(SourceFiles::SourceFileNode *node = files->nodes[file]; node; node = node->next) {
838 stream << node->file->file.local() << endl; //source
839 stream << node->file->type << endl; //type
840
841 //depends
842 stream << ";";
843 if(node->file->deps) {
844 for(int depend = 0; depend < node->file->deps->used_nodes; ++depend) {
845 if(depend)
846 stream << ";";
847 stream << node->file->deps->children[depend]->file.local();
848 }
849 }
850 stream << endl;
851
852 stream << node->file->mocable << endl; //mocable
853 stream << endl; //just for human readability
854 }
855 }
856 }
857 stream.flush();
858 file.close();
859 }
860#else
861 Q_UNUSED(cf);
862#endif
863}
864
865void QMakeSourceFileInfo::loadCache(const QString &cf)
866{
867 if(cf.isEmpty())
868 return;
869
870#ifdef QMAKE_USE_CACHE
871 QMakeLocalFileName cache_file(cf);
872 int fd = open(QMakeLocalFileName(cf).local().toLatin1(), O_RDONLY);
873 if(fd == -1)
874 return;
875 QFileInfo cache_fi = findFileInfo(cache_file);
876 if(!cache_fi.exists() || cache_fi.isDir())
877 return;
878
879 QFile file;
880 if(!file.open(QIODevice::ReadOnly, fd))
881 return;
882 QTextStream stream(&file);
883
884 if(stream.readLine() == qmake_version()) { //version check
885 stream.skipWhiteSpace();
886
887 bool verified = true;
888 { //cache verification
889 QMap<QString, QStringList> verify;
890 int len = stream.readLine().toInt();
891 for(int i = 0; i < len; ++i) {
892 QString var = stream.readLine();
893 QString val = stream.readLine();
894 verify.insert(var, val.split(';', QString::SkipEmptyParts));
895 }
896 verified = verifyCache(verify);
897 }
898 if(verified) {
899 stream.skipWhiteSpace();
900 if(!files)
901 files = new SourceFiles;
902 while(!stream.atEnd()) {
903 QString source = stream.readLine();
904 QString type = stream.readLine();
905 QString depends = stream.readLine();
906 QString mocable = stream.readLine();
907 stream.skipWhiteSpace();
908
909 QMakeLocalFileName fn(source);
910 QFileInfo fi = findFileInfo(fn);
911
912 SourceFile *file = files->lookupFile(fn);
913 if(!file) {
914 file = new SourceFile;
915 file->file = fn;
916 files->addFile(file);
917 file->type = (SourceFileType)type.toInt();
918 file->exists = fi.exists();
919 }
920 if(fi.exists() && fi.lastModified() < cache_fi.lastModified()) {
921 if(!file->dep_checked) { //get depends
922 if(!file->deps)
923 file->deps = new SourceDependChildren;
924 file->dep_checked = true;
925 QStringList depend_list = depends.split(";", QString::SkipEmptyParts);
926 for(int depend = 0; depend < depend_list.size(); ++depend) {
927 QMakeLocalFileName dep_fn(depend_list.at(depend));
928 QFileInfo dep_fi(findFileInfo(dep_fn));
929 SourceFile *dep = files->lookupFile(dep_fn);
930 if(!dep) {
931 dep = new SourceFile;
932 dep->file = dep_fn;
933 dep->exists = dep_fi.exists();
934 dep->type = QMakeSourceFileInfo::TYPE_UNKNOWN;
935 files->addFile(dep);
936 }
937 dep->included_count++;
938 file->deps->addChild(dep);
939 }
940 }
941 if(!file->moc_checked) { //get mocs
942 file->moc_checked = true;
943 file->mocable = mocable.toInt();
944 }
945 }
946 }
947 }
948 }
949#endif
950}
951
952QMap<QString, QStringList> QMakeSourceFileInfo::getCacheVerification()
953{
954 return QMap<QString, QStringList>();
955}
956
957bool QMakeSourceFileInfo::verifyCache(const QMap<QString, QStringList> &v)
958{
959 return v == getCacheVerification();
960}
961
962QT_END_NAMESPACE
963

Warning: That file was not part of the compilation database. It may have many parsing errors.