summaryrefslogtreecommitdiff
path: root/qmake/project.cpp
authorzecke <zecke>2004-07-15 17:36:57 (UTC)
committer zecke <zecke>2004-07-15 17:36:57 (UTC)
commit323e9a7472a110b4befba7320540263147505bae (patch) (unidiff)
tree14c810bdb9c0603a30356b17b4bdf9ccb72741c6 /qmake/project.cpp
parentaa292b322f1ecb43dd8f4e3cd295855730dd9f59 (diff)
downloadopie-323e9a7472a110b4befba7320540263147505bae.zip
opie-323e9a7472a110b4befba7320540263147505bae.tar.gz
opie-323e9a7472a110b4befba7320540263147505bae.tar.bz2
Manually updatet to qmake1.06a which includes support for precompiled
headers. Opies 'PRO' keyword was already reintroduced
Diffstat (limited to 'qmake/project.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--qmake/project.cpp662
1 files changed, 488 insertions, 174 deletions
diff --git a/qmake/project.cpp b/qmake/project.cpp
index 834823d..8aa6ff7 100644
--- a/qmake/project.cpp
+++ b/qmake/project.cpp
@@ -1,14 +1,12 @@
1/**************************************************************************** 1/****************************************************************************
2** $Id$ 2**
3** 3**
4** Definition of ________ class. 4** Implementation of QMakeProject class.
5** 5**
6** Created : 970521 6** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
7** 7**
8** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. 8** This file is part of qmake.
9**
10** This file is part of the network module of the Qt GUI Toolkit.
11** 9**
12** This file may be distributed under the terms of the Q Public License 10** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file 11** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file. 12** LICENSE.QPL included in the packaging of this file.
@@ -35,8 +33,9 @@
35** 33**
36**********************************************************************/ 34**********************************************************************/
37 35
38#include "project.h" 36#include "project.h"
37#include "property.h"
39#include "option.h" 38#include "option.h"
40#include <qfile.h> 39#include <qfile.h>
41#include <qdir.h> 40#include <qdir.h>
42#include <qregexp.h> 41#include <qregexp.h>
@@ -57,81 +56,157 @@
57struct parser_info { 56struct parser_info {
58 QString file; 57 QString file;
59 int line_no; 58 int line_no;
60} parser; 59} parser;
60
61static void qmake_error_msg(const char *msg) 61static void qmake_error_msg(const char *msg)
62{ 62{
63 fprintf(stderr, "%s:%d: %s\n", parser.file.latin1(), parser.line_no, msg); 63 fprintf(stderr, "%s:%d: %s\n", parser.file.latin1(), parser.line_no, msg);
64} 64}
65 65
66QStringList qmake_mkspec_paths()
67{
68 QStringList ret;
69 const QString concat = QDir::separator() + QString("mkspecs");
70 if(const char *qmakepath = getenv("QMAKEPATH")) {
71#ifdef Q_OS_WIN
72 QStringList lst = QStringList::split(';', qmakepath);
73 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it) {
74 QStringList lst2 = QStringList::split(':', (*it));
75 for(QStringList::Iterator it2 = lst2.begin(); it2 != lst2.end(); ++it2)
76 ret << ((*it2) + concat);
77 }
78#else
79 QStringList lst = QStringList::split(':', qmakepath);
80 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it)
81 ret << ((*it) + concat);
82#endif
83 }
84 if(const char *qtdir = getenv("QTDIR"))
85 ret << (QString(qtdir) + concat);
86#ifdef QT_INSTALL_PREFIX
87 ret << (QT_INSTALL_PREFIX + concat);
88#endif
89#if defined(HAVE_QCONFIG_CPP)
90 ret << (qInstallPath() + concat);
91#endif
92#ifdef QT_INSTALL_DATA
93 ret << (QT_INSTALL_DATA + concat);
94#endif
95#if defined(HAVE_QCONFIG_CPP)
96 ret << (qInstallPathData() + concat);
97#endif
98
99 /* prefer $QTDIR if it is set */
100 if (getenv("QTDIR"))
101 ret << getenv("QTDIR");
102 ret << qInstallPathData();
103 return ret;
104}
105
66static QString varMap(const QString &x) 106static QString varMap(const QString &x)
67{ 107{
68 QString ret(x); 108 QString ret(x);
69 if(ret.startsWith("TMAKE")) //tmake no more! 109 if(ret.startsWith("TMAKE")) //tmake no more!
70 ret = "QMAKE" + ret.mid(5); 110 ret = "QMAKE" + ret.mid(5);
71 if(ret == "INTERFACES") 111 else if(ret == "INTERFACES")
72 ret = "FORMS"; 112 ret = "FORMS";
73 if(ret == "QMAKE_POST_BUILD") 113 else if(ret == "QMAKE_POST_BUILD")
74 ret = "QMAKE_POST_LINK"; 114 ret = "QMAKE_POST_LINK";
75 if(ret == "TARGETDEPS") 115 else if(ret == "TARGETDEPS")
76 ret = "POST_TARGETDEPS"; 116 ret = "POST_TARGETDEPS";
117 else if(ret == "LIBPATH")
118 ret = "QMAKE_LIBDIR";
119 else if(ret == "QMAKE_EXT_MOC")
120 ret = "QMAKE_EXT_CPP_MOC";
121 else if(ret == "QMAKE_MOD_MOC")
122 ret = "QMAKE_H_MOD_MOC";
123 else if(ret == "QMAKE_LFLAGS_SHAPP")
124 ret = "QMAKE_LFLAGS_APP";
125 else if(ret == "PRECOMPH")
126 ret = "PRECOMPILED_HEADER";
127 else if(ret == "PRECOMPCPP")
128 ret = "PRECOMPILED_SOURCE";
129 else if(ret == "INCPATH")
130 ret = "INCLUDEPATH";
77 return ret; 131 return ret;
78} 132}
79 133
80static QStringList split_arg_list(const QString &params) 134static QStringList split_arg_list(const QString &params)
81{ 135{
82 QStringList args;
83 int last = 0, parens = 0;
84 QChar quote = 0; 136 QChar quote = 0;
85 for(int x = 0; x < (int)params.length(); x++) { 137 QStringList args;
86 if(params[x] == ')') { 138 for(int x = 0, last = 0, parens = 0; x <= (int)params.length(); x++) {
139 if(x == (int)params.length()) {
140 QString mid = params.mid(last, x - last).stripWhiteSpace();
141 if(mid[(int)mid.length()-1] == quote)
142 mid.truncate(1);
143 args << mid;
144 } else if(params[x] == ')') {
87 parens--; 145 parens--;
88 } else if(params[x] == '(') { 146 } else if(params[x] == '(') {
89 parens++; 147 parens++;
90 } else if(params[x] == quote) { 148 } else if(params[x] == quote) {
91 quote = 0; 149 quote = 0;
92 } else if(params[x] == '\'' || params[x] == '"') { 150 } else if(params[x] == '\'' || params[x] == '"') {
93 quote = params[x]; 151 quote = params[x];
94 } else if(!parens && !quote && params[x] == ',') { 152 } else if(!parens && !quote && params[x] == ',') {
95 args << params.mid(last, x - last); 153 args << params.mid(last, x - last).stripWhiteSpace();
96 last = x+1; 154 last = x+1;
97 } 155 }
98 } 156 }
99 if(last != (int)params.length())
100 args << params.mid(last);
101 return args; 157 return args;
102} 158}
103 159
104static QStringList split_value_list(const QString &vals, bool do_semicolon=FALSE) 160static QStringList split_value_list(const QString &vals, bool do_semicolon=FALSE)
105{ 161{
106 int last = 0; 162 QString build;
107 QStringList ret; 163 QStringList ret;
108 QValueStack<QChar> quote; 164 QValueStack<QChar> quote;
109 for(int x = 0; x < (int)vals.length(); x++) { 165 for(int x = 0; x < (int)vals.length(); x++) {
110 if(!quote.isEmpty() && vals[x] == quote.top()) { 166 if(x != (int)vals.length()-1 && vals[x] == '\\' && (vals[x+1] == '\'' || vals[x+1] == '"'))
167 build += vals[x++]; //get that 'escape'
168 else if(!quote.isEmpty() && vals[x] == quote.top())
111 quote.pop(); 169 quote.pop();
112 } else if(vals[x] == '\'' || vals[x] == '"') { 170 else if(vals[x] == '\'' || vals[x] == '"')
113 quote.push(vals[x]); 171 quote.push(vals[x]);
114 } else if(quote.isEmpty() && 172
115 ((do_semicolon && vals[x] == ';') || vals[x] == ' ')) { 173 if(quote.isEmpty() && ((do_semicolon && vals[x] == ';') || vals[x] == ' ')) {
116 ret << vals.mid(last, x - last); 174 ret << build;
117 last = x+1; 175 build = "";
176 } else {
177 build += vals[x];
118 } 178 }
119 } 179 }
120 if(last != (int)vals.length()) 180 if(!build.isEmpty())
121 ret << vals.mid(last); 181 ret << build;
122 return ret; 182 return ret;
123} 183}
124 184
125QMakeProject::QMakeProject() 185QMakeProject::QMakeProject()
126{ 186{
187 prop = NULL;
188}
189
190QMakeProject::QMakeProject(QMakeProperty *p)
191{
192 prop = p;
193}
194
195void
196QMakeProject::reset()
197{
198 /* scope blocks start at true */
199 test_status = TestNone;
200 scope_flag = 0x01;
201 scope_block = 0;
127} 202}
128 203
129bool 204bool
130QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place) 205QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
131{ 206{
132 QString s = t.simplifyWhiteSpace(); 207 QString s = t.simplifyWhiteSpace();
133 int hash_mark = s.find('#'); 208 int hash_mark = s.find("#");
134 if(hash_mark != -1) //good bye comments 209 if(hash_mark != -1) //good bye comments
135 s = s.left(hash_mark); 210 s = s.left(hash_mark);
136 if(s.isEmpty()) /* blank_line */ 211 if(s.isEmpty()) /* blank_line */
137 return TRUE; 212 return TRUE;
@@ -146,9 +221,9 @@ QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
146 return TRUE; 221 return TRUE;
147 } 222 }
148 if(!(scope_flag & (0x01 << scope_block))) { 223 if(!(scope_flag & (0x01 << scope_block))) {
149 /* adjust scope for each block which appears on a single line */ 224 /* adjust scope for each block which appears on a single line */
150 for(int i = (s.contains('{')-s.contains('}')); i; i--) 225 for(int i = (s.contains('{')-s.contains('}')); i>0; i--)
151 scope_flag &= ~(0x01 << (++scope_block)); 226 scope_flag &= ~(0x01 << (++scope_block));
152 debug_msg(1, "Project Parser: %s:%d : Ignored due to block being false.", 227 debug_msg(1, "Project Parser: %s:%d : Ignored due to block being false.",
153 parser.file.latin1(), parser.line_no); 228 parser.file.latin1(), parser.line_no);
154 return TRUE; 229 return TRUE;
@@ -227,9 +302,9 @@ QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
227 test_status = (test ? TestFound : TestSeek); 302 test_status = (test ? TestFound : TestSeek);
228 return TRUE; /* assume we are done */ 303 return TRUE; /* assume we are done */
229 } 304 }
230 } else { 305 } else {
231 test = isActiveConfig(comp_scope.stripWhiteSpace(), TRUE); 306 test = isActiveConfig(comp_scope.stripWhiteSpace(), TRUE, &place);
232 } 307 }
233 if(invert_test) 308 if(invert_test)
234 test = !test; 309 test = !test;
235 } 310 }
@@ -247,27 +322,37 @@ QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
247 scope_flag &= ~(0x01 << (++scope_block)); 322 scope_flag &= ~(0x01 << (++scope_block));
248 debug_msg(1, "Project Parser: %s:%d : Entering block %d (%d).", parser.file.latin1(), 323 debug_msg(1, "Project Parser: %s:%d : Entering block %d (%d).", parser.file.latin1(),
249 parser.line_no, scope_block, !scope_failed); 324 parser.line_no, scope_block, !scope_failed);
250 } 325 }
326 } else if(!parens && *d == '}') {
327 if(!scope_block) {
328 warn_msg(WarnParser, "Possible braces mismatch %s:%d", parser.file.latin1(), parser.line_no);
329 } else {
330 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(),
331 parser.line_no, scope_block);
332 --scope_block;
333 }
251 } else { 334 } else {
252 var += *d; 335 var += *d;
253 } 336 }
254 d++; 337 d++;
255 } 338 }
339 var = var.stripWhiteSpace();
256 if(!scope_count || (scope_count == 1 && else_line)) 340 if(!scope_count || (scope_count == 1 && else_line))
257 test_status = TestNone; 341 test_status = TestNone;
258 else if(!else_line || test_status != TestFound) 342 else if(!else_line || test_status != TestFound)
259 test_status = (scope_failed ? TestSeek : TestFound); 343 test_status = (scope_failed ? TestSeek : TestFound);
260 if(scope_failed) 344 if(scope_failed)
261 return TRUE; /* oh well */ 345 return TRUE; /* oh well */
262 if(!*d) { 346 if(!*d) {
263 if(!var.isEmpty()) 347 if(!var.stripWhiteSpace().isEmpty())
264 qmake_error_msg("Parse Error ('" + s + "')"); 348 qmake_error_msg("Parse Error ('" + s + "')");
265 return var.isEmpty(); /* allow just a scope */ 349 return var.isEmpty(); /* allow just a scope */
266 } 350 }
267 351
268 SKIP_WS(d); 352 SKIP_WS(d);
269 for( ; *d && op.find('=') == -1; op += *(d++)); 353 for( ; *d && op.find('=') == -1; op += *(d++))
354 ;
270 op.replace(QRegExp("\\s"), ""); 355 op.replace(QRegExp("\\s"), "");
271 356
272 SKIP_WS(d); 357 SKIP_WS(d);
273 QString vals(d); /* vals now contains the space separated list of values */ 358 QString vals(d); /* vals now contains the space separated list of values */
@@ -283,18 +368,17 @@ QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
283 vals.latin1(), parser.file.latin1(), parser.line_no); 368 vals.latin1(), parser.file.latin1(), parser.line_no);
284 } 369 }
285 doVariableReplace(vals, place); 370 doVariableReplace(vals, place);
286 371
287 var = var.stripWhiteSpace();
288#undef SKIP_WS 372#undef SKIP_WS
289 373
290 if(!var.isEmpty() && Option::mkfile::do_preprocess) { 374 if(!var.isEmpty() && Option::mkfile::do_preprocess) {
291 static QString last_file("*none*"); 375 static QString last_file("*none*");
292 if(parser.file != last_file) { 376 if(parser.file != last_file) {
293 fprintf(stderr, "#file %s:%d\n", parser.file.latin1(), parser.line_no); 377 fprintf(stdout, "#file %s:%d\n", parser.file.latin1(), parser.line_no);
294 last_file = parser.file; 378 last_file = parser.file;
295 } 379 }
296 fprintf(stderr, "%s %s %s\n", var.latin1(), op.latin1(), vals.latin1()); 380 fprintf(stdout, "%s %s %s\n", var.latin1(), op.latin1(), vals.latin1());
297 } 381 }
298 var = varMap(var); //backwards compatability 382 var = varMap(var); //backwards compatability
299 383
300 /* vallist is the broken up list of values */ 384 /* vallist is the broken up list of values */
@@ -304,9 +388,9 @@ QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
304 var.latin1(), parser.file.latin1(), parser.line_no); 388 var.latin1(), parser.file.latin1(), parser.line_no);
305 389
306 QStringList &varlist = place[var]; /* varlist is the list in the symbol table */ 390 QStringList &varlist = place[var]; /* varlist is the list in the symbol table */
307 debug_msg(1, "Project Parser: %s:%d :%s: :%s: (%s)", parser.file.latin1(), parser.line_no, 391 debug_msg(1, "Project Parser: %s:%d :%s: :%s: (%s)", parser.file.latin1(), parser.line_no,
308 var.latin1(), op.latin1(), vallist.join(" :: ").latin1()); 392 var.latin1(), op.latin1(), vallist.isEmpty() ? "" : vallist.join(" :: ").latin1());
309 393
310 /* now do the operation */ 394 /* now do the operation */
311 if(op == "~=") { 395 if(op == "~=") {
312 if(vallist.count() != 1) { 396 if(vallist.count() != 1) {
@@ -368,12 +452,9 @@ QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
368bool 452bool
369QMakeProject::read(const QString &file, QMap<QString, QStringList> &place) 453QMakeProject::read(const QString &file, QMap<QString, QStringList> &place)
370{ 454{
371 parser_info pi = parser; 455 parser_info pi = parser;
372 /* scope blocks start at true */ 456 reset();
373 test_status = TestNone;
374 scope_flag = 0x01;
375 scope_block = 0;
376 457
377 QString filename = Option::fixPathToLocalOS(file); 458 QString filename = Option::fixPathToLocalOS(file);
378 doVariableReplace(filename, place); 459 doVariableReplace(filename, place);
379 bool ret = FALSE, using_stdin = FALSE; 460 bool ret = FALSE, using_stdin = FALSE;
@@ -394,16 +475,17 @@ QMakeProject::read(const QString &file, QMap<QString, QStringList> &place)
394 while ( !t.eof() ) { 475 while ( !t.eof() ) {
395 parser.line_no++; 476 parser.line_no++;
396 line = t.readLine().stripWhiteSpace(); 477 line = t.readLine().stripWhiteSpace();
397 int prelen = line.length(); 478 int prelen = line.length();
398 { 479
399 int hash_mark = line.find('#'); 480 int hash_mark = line.find("#");
400 if(hash_mark != -1) //bye comments 481 if(hash_mark != -1) //good bye comments
401 line = line.left(hash_mark); 482 line = line.left(hash_mark);
402 }
403 if(!line.isEmpty() && line.right(1) == "\\") { 483 if(!line.isEmpty() && line.right(1) == "\\") {
404 line.truncate(line.length() - 1); 484 if (!line.startsWith("#")) {
405 s += line + " "; 485 line.truncate(line.length() - 1);
486 s += line + " ";
487 }
406 } else if(!line.isEmpty() || (line.isEmpty() && !prelen)) { 488 } else if(!line.isEmpty() || (line.isEmpty() && !prelen)) {
407 if(s.isEmpty() && line.isEmpty()) 489 if(s.isEmpty() && line.isEmpty())
408 continue; 490 continue;
409 if(!line.isEmpty()) 491 if(!line.isEmpty())
@@ -418,30 +500,32 @@ QMakeProject::read(const QString &file, QMap<QString, QStringList> &place)
418 if(!using_stdin) 500 if(!using_stdin)
419 qfile.close(); 501 qfile.close();
420 } 502 }
421 parser = pi; 503 parser = pi;
504 if(scope_block != 0)
505 warn_msg(WarnParser, "%s: Unterminated conditional at end of file.",
506 file.latin1());
422 return ret; 507 return ret;
423} 508}
424 509
425bool 510bool
426QMakeProject::read(const QString &project, const QString &, bool just_project) 511QMakeProject::read(const QString &project, const QString &, uchar cmd)
427{ 512{
428 if(just_project) { //nothing more, nothing less 513 pfile = project;
429 pfile = project; 514 return read(cmd);
430 if(pfile != "-" && !QFile::exists(pfile) && pfile.right(4) != ".pro") 515}
431 pfile += ".pro";
432 return read(pfile, vars);
433 }
434 516
517bool
518QMakeProject::read(uchar cmd)
519{
435 if(cfile.isEmpty()) { 520 if(cfile.isEmpty()) {
436 // hack to get the Option stuff in there 521 // hack to get the Option stuff in there
437 base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext; 522 base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext;
438 base_vars["QMAKE_EXT_H"] = Option::h_ext; 523 base_vars["QMAKE_EXT_H"] = Option::h_ext;
439 if(!Option::user_template_prefix.isEmpty()) 524 if(!Option::user_template_prefix.isEmpty())
440 base_vars["TEMPLATE_PREFIX"] = Option::user_template_prefix; 525 base_vars["TEMPLATE_PREFIX"] = Option::user_template_prefix;
441 526
442 /* parse the cache */ 527 if(cmd & ReadCache && Option::mkfile::do_cache) {/* parse the cache */
443 if(Option::mkfile::do_cache) {
444 if(Option::mkfile::cachefile.isEmpty()) { //find it as it has not been specified 528 if(Option::mkfile::cachefile.isEmpty()) { //find it as it has not been specified
445 QString dir = QDir::convertSeparators(Option::output_dir); 529 QString dir = QDir::convertSeparators(Option::output_dir);
446 while(!QFile::exists((Option::mkfile::cachefile = dir + 530 while(!QFile::exists((Option::mkfile::cachefile = dir +
447 QDir::separator() + ".qmake.cache"))) { 531 QDir::separator() + ".qmake.cache"))) {
@@ -461,98 +545,109 @@ QMakeProject::read(const QString &project, const QString &, bool just_project)
461 if(Option::mkfile::qmakespec.isEmpty() && !cache["QMAKESPEC"].isEmpty()) 545 if(Option::mkfile::qmakespec.isEmpty() && !cache["QMAKESPEC"].isEmpty())
462 Option::mkfile::qmakespec = cache["QMAKESPEC"].first(); 546 Option::mkfile::qmakespec = cache["QMAKESPEC"].first();
463 } 547 }
464 } 548 }
465 /* parse mkspec */ 549 if(cmd & ReadConf) { /* parse mkspec */
466 QStringList mkspec_roots; 550 QStringList mkspec_roots = qmake_mkspec_paths();
467 /* prefer $QTDIR if it is set */
468 if (getenv("QTDIR"))
469 mkspec_roots << getenv("QTDIR");
470 mkspec_roots << qInstallPathData();
471 if(Option::mkfile::qmakespec.isEmpty()) {
472 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
473 QString mkspec = (*it) + QDir::separator() + QString("mkspecs") +
474 QDir::separator() + "default";
475 if(QFile::exists(mkspec)) {
476 Option::mkfile::qmakespec = mkspec;
477 break;
478 }
479 }
480 if(Option::mkfile::qmakespec.isEmpty()) { 551 if(Option::mkfile::qmakespec.isEmpty()) {
481 fprintf(stderr, "QMAKESPEC has not been set, so configuration cannot be deduced.\n"); 552 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
482 return FALSE; 553 QString mkspec = (*it) + QDir::separator() + "default";
554 if(QFile::exists(mkspec)) {
555 Option::mkfile::qmakespec = mkspec;
556 break;
557 }
558 }
559 if(Option::mkfile::qmakespec.isEmpty()) {
560 fprintf(stderr, "QMAKESPEC has not been set, so configuration cannot be deduced.\n");
561 return FALSE;
562 }
483 } 563 }
484 }
485 564
486 if(QDir::isRelativePath(Option::mkfile::qmakespec)) { 565 if(QDir::isRelativePath(Option::mkfile::qmakespec)) {
487 bool found_mkspec = FALSE; 566 bool found_mkspec = FALSE;
488 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) { 567 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
489 QString mkspec = (*it) + QDir::separator() + QString("mkspecs") + 568 QString mkspec = (*it) + QDir::separator() + Option::mkfile::qmakespec;
490 QDir::separator() + Option::mkfile::qmakespec; 569 if(QFile::exists(mkspec)) {
491 if(QFile::exists(mkspec)) { 570 found_mkspec = TRUE;
492 found_mkspec = TRUE; 571 Option::mkfile::qmakespec = mkspec;
493 Option::mkfile::qmakespec = mkspec; 572 break;
494 break; 573 }
574 }
575 if(!found_mkspec) {
576 fprintf(stderr, "Could not find mkspecs for your QMAKESPEC after trying:\n\t%s\n",
577 mkspec_roots.join("\n\t").latin1());
578 return FALSE;
495 } 579 }
496 } 580 }
497 if(!found_mkspec) { 581
498 fprintf(stderr, "Could not find mkspecs for your QMAKESPEC after trying:\n\t%s\n", 582 /* parse qmake configuration */
499 mkspec_roots.join("\n\t").latin1()); 583 while(Option::mkfile::qmakespec.endsWith(QString(QChar(QDir::separator()))))
584 Option::mkfile::qmakespec.truncate(Option::mkfile::qmakespec.length()-1);
585 QString spec = Option::mkfile::qmakespec + QDir::separator() + "qmake.conf";
586 if(!QFile::exists(spec) &&
587 QFile::exists(Option::mkfile::qmakespec + QDir::separator() + "tmake.conf"))
588 spec = Option::mkfile::qmakespec + QDir::separator() + "tmake.conf";
589 debug_msg(1, "QMAKESPEC conf: reading %s", spec.latin1());
590 if(!read(spec, base_vars)) {
591 fprintf(stderr, "Failure to read QMAKESPEC conf file %s.\n", spec.latin1());
500 return FALSE; 592 return FALSE;
501 } 593 }
594 if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) {
595 debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.latin1());
596 read(Option::mkfile::cachefile, base_vars);
597 }
598 }
599 if(cmd & ReadCmdLine) {
600 /* commandline */
601 cfile = pfile;
602 parser.line_no = 1; //really arg count now.. duh
603 parser.file = "(internal)";
604 reset();
605 for(QStringList::Iterator it = Option::before_user_vars.begin();
606 it != Option::before_user_vars.end(); ++it) {
607 if(!parse((*it), base_vars)) {
608 fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1());
609 return FALSE;
610 }
611 parser.line_no++;
612 }
502 } 613 }
614 }
615
616 vars = base_vars; /* start with the base */
503 617
504 /* parse qmake configuration */ 618 if(cmd & ReadProFile) { /* parse project file */
505 QString spec = Option::mkfile::qmakespec + QDir::separator() + "qmake.conf"; 619 debug_msg(1, "Project file: reading %s", pfile.latin1());
506 debug_msg(1, "QMAKESPEC conf: reading %s", spec.latin1()); 620 if(pfile != "-" && !QFile::exists(pfile) && !pfile.endsWith(".pro"))
507 if(!read(spec, base_vars)) { 621 pfile += ".pro";
508 fprintf(stderr, "Failure to read QMAKESPEC conf file %s.\n", spec.latin1()); 622 if(!read(pfile, vars))
509 return FALSE; 623 return FALSE;
510 } 624 }
511 if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) {
512 debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.latin1());
513 read(Option::mkfile::cachefile, base_vars);
514 }
515 625
516 /* commandline */ 626 if(cmd & ReadPostFiles) { /* parse post files */
517 cfile = project; 627 const QStringList l = vars["QMAKE_POST_INCLUDE_FILES"];
628 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
629 read((*it), vars);
630 }
631
632 if(cmd & ReadCmdLine) {
518 parser.line_no = 1; //really arg count now.. duh 633 parser.line_no = 1; //really arg count now.. duh
519 parser.file = "(internal)"; 634 parser.file = "(internal)";
520 for(QStringList::Iterator it = Option::before_user_vars.begin(); 635 reset();
521 it != Option::before_user_vars.end(); ++it) { 636 for(QStringList::Iterator it = Option::after_user_vars.begin();
522 if(!parse((*it), base_vars)) { 637 it != Option::after_user_vars.end(); ++it) {
638 if(!parse((*it), vars)) {
523 fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1()); 639 fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1());
524 return FALSE; 640 return FALSE;
525 } 641 }
526 parser.line_no++; 642 parser.line_no++;
527 } 643 }
528 } 644 }
529 645
530 /* parse project file */
531 debug_msg(1, "Project file: reading %s", project.latin1());
532 vars = base_vars; /* start with the base */
533
534 pfile = project;
535 if(pfile != "-" && !QFile::exists(pfile) && pfile.right(4) != ".pro")
536 pfile += ".pro";
537
538 if(!read(pfile, vars))
539 return FALSE;
540
541 parser.line_no = 1; //really arg count now.. duh
542 parser.file = "(internal)";
543 for(QStringList::Iterator it = Option::after_user_vars.begin();
544 it != Option::after_user_vars.end(); ++it) {
545 if(!parse((*it), vars)) {
546 fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1());
547 return FALSE;
548 }
549 parser.line_no++;
550 }
551
552 /* now let the user override the template from an option.. */ 646 /* now let the user override the template from an option.. */
553 if(!Option::user_template.isEmpty()) { 647 if(!Option::user_template.isEmpty()) {
554 debug_msg(1, "Overriding TEMPLATE (%s) with: %s", vars["TEMPLATE"].first().latin1(), Option::user_template.latin1()); 648 debug_msg(1, "Overriding TEMPLATE (%s) with: %s", vars["TEMPLATE"].first().latin1(),
649 Option::user_template.latin1());
555 vars["TEMPLATE"].clear(); 650 vars["TEMPLATE"].clear();
556 vars["TEMPLATE"].append(Option::user_template); 651 vars["TEMPLATE"].append(Option::user_template);
557 } 652 }
558 653
@@ -560,11 +655,10 @@ QMakeProject::read(const QString &project, const QString &, bool just_project)
560 if(templ.isEmpty()) 655 if(templ.isEmpty())
561 templ.append(QString("app")); 656 templ.append(QString("app"));
562 else if(vars["TEMPLATE"].first().endsWith(".t")) 657 else if(vars["TEMPLATE"].first().endsWith(".t"))
563 templ = QStringList(templ.first().left(templ.first().length() - 2)); 658 templ = QStringList(templ.first().left(templ.first().length() - 2));
564 if ( !Option::user_template_prefix.isEmpty() ) { 659 if ( !Option::user_template_prefix.isEmpty() )
565 templ.first().prepend(Option::user_template_prefix); 660 templ.first().prepend(Option::user_template_prefix);
566 }
567 661
568 if(vars["TARGET"].isEmpty()) { 662 if(vars["TARGET"].isEmpty()) {
569 // ### why not simply use: 663 // ### why not simply use:
570 // QFileInfo fi(pfile); 664 // QFileInfo fi(pfile);
@@ -592,9 +686,9 @@ QMakeProject::read(const QString &project, const QString &, bool just_project)
592 return TRUE; 686 return TRUE;
593} 687}
594 688
595bool 689bool
596QMakeProject::isActiveConfig(const QString &x, bool regex) 690QMakeProject::isActiveConfig(const QString &x, bool regex, QMap<QString, QStringList> *place)
597{ 691{
598 if(x.isEmpty()) 692 if(x.isEmpty())
599 return TRUE; 693 return TRUE;
600 694
@@ -636,9 +730,9 @@ QMakeProject::isActiveConfig(const QString &x, bool regex)
636 } 730 }
637#endif 731#endif
638 732
639 733
640 QStringList &configs = vars["CONFIG"]; 734 QStringList &configs = (place ? (*place)["CONFIG"] : vars["CONFIG"]);
641 for(QStringList::Iterator it = configs.begin(); it != configs.end(); ++it) { 735 for(QStringList::Iterator it = configs.begin(); it != configs.end(); ++it) {
642 if((regex && re.exactMatch((*it))) || (!regex && (*it) == x)) 736 if((regex && re.exactMatch((*it))) || (!regex && (*it) == x))
643 if(re.exactMatch((*it))) 737 if(re.exactMatch((*it)))
644 return TRUE; 738 return TRUE;
@@ -776,9 +870,12 @@ QMakeProject::doProjectTest(const QString& func, QStringList args, QMap<QString,
776 return FALSE; 870 return FALSE;
777 } 871 }
778 return vars[args[0]].isEmpty(); 872 return vars[args[0]].isEmpty();
779 } else if(func == "include" || func == "load") { 873 } else if(func == "include" || func == "load") {
780 if(args.count() != 1) { 874 QString seek_var;
875 if(args.count() == 2 && func == "include") {
876 seek_var = args[1];
877 } else if(args.count() != 1) {
781 QString func_desc = "include(file)"; 878 QString func_desc = "include(file)";
782 if(func == "load") 879 if(func == "load")
783 func_desc = "load(feature)"; 880 func_desc = "load(feature)";
784 fprintf(stderr, "%s:%d: %s requires one argument.\n", parser.file.latin1(), 881 fprintf(stderr, "%s:%d: %s requires one argument.\n", parser.file.latin1(),
@@ -793,53 +890,117 @@ QMakeProject::doProjectTest(const QString& func, QStringList args, QMap<QString,
793 if(func == "load") { 890 if(func == "load") {
794 if(!file.endsWith(Option::prf_ext)) 891 if(!file.endsWith(Option::prf_ext))
795 file += Option::prf_ext; 892 file += Option::prf_ext;
796 if(file.find(Option::dir_sep) == -1 || !QFile::exists(file)) { 893 if(file.find(Option::dir_sep) == -1 || !QFile::exists(file)) {
797 if(QFile::exists(Option::mkfile::qmakespec + QDir::separator() + file)) { 894 bool found = FALSE;
798 file.prepend(Option::mkfile::qmakespec + QDir::separator()); 895 const QString concat = QDir::separator() + QString("mkspecs") +
799 } else { 896 QDir::separator() + QString("features");
800 bool found = FALSE; 897 QStringList feature_roots;
801 QStringList feature_roots; 898 if(const char *mkspec_path = getenv("QMAKEFEATURES")) {
802 if(getenv("QTDIR")) 899#ifdef Q_OS_WIN
803 feature_roots << getenv("QTDIR"); 900 QStringList lst = QStringList::split(';', mkspec_path);
901 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it)
902 feature_roots += QStringList::split(':', (*it));
903#else
904 feature_roots += QStringList::split(':', mkspec_path);
905#endif
906 }
907 if(const char *qmakepath = getenv("QMAKEPATH")) {
908#ifdef Q_OS_WIN
909 QStringList lst = QStringList::split(';', qmakepath);
910 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it) {
911 QStringList lst2 = QStringList::split(':', (*it));
912 for(QStringList::Iterator it2 = lst2.begin(); it2 != lst2.end(); ++it2)
913 feature_roots << ((*it2) + concat);
914 }
915#else
916 QStringList lst = QStringList::split(':', qmakepath);
917 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it)
918 feature_roots << ((*it) + concat);
919#endif
920 }
921 feature_roots << Option::mkfile::qmakespec;
922 if(const char *qtdir = getenv("QTDIR"))
923 feature_roots << (qtdir + concat);
804#ifdef QT_INSTALL_PREFIX 924#ifdef QT_INSTALL_PREFIX
805 feature_roots << QT_INSTALL_PREFIX; 925 feature_roots << (QT_INSTALL_PREFIX + concat);
926#endif
927#if defined(HAVE_QCONFIG_CPP)
928 feature_roots << (qInstallPath() + concat);
806#endif 929#endif
807#ifdef QT_INSTALL_DATA 930#ifdef QT_INSTALL_DATA
808 feature_roots << QT_INSTALL_DATA; 931 feature_roots << (QT_INSTALL_DATA + concat);
809#endif 932#endif
810 for(QStringList::Iterator it = feature_roots.begin(); it != feature_roots.end(); ++it) { 933#if defined(HAVE_QCONFIG_CPP)
811 QString prf = (*it) + QDir::separator() + QString("mkspecs") + 934 feature_roots << (qInstallPathData() + concat);
812 QDir::separator() + QString("features") + QDir::separator() + file; 935#endif
813 if(QFile::exists(prf)) { 936 for(QStringList::Iterator it = feature_roots.begin(); it != feature_roots.end(); ++it) {
814 found = TRUE; 937 QString prf = (*it) + QDir::separator() + file;
815 file = prf; 938 if(QFile::exists(prf)) {
816 break; 939 found = TRUE;
817 } 940 file = prf;
818 } 941 break;
819 if(!found) {
820 printf("Project LOAD(): Feature %s cannot be found.\n", args.first().latin1());
821 exit(3);
822 } 942 }
823 } 943 }
944 if(!found) {
945 printf("Project LOAD(): Feature %s cannot be found.\n", args.first().latin1());
946 exit(3);
947 }
948 }
949 }
950 if(QDir::isRelativePath(file)) {
951 QStringList include_roots;
952 include_roots << Option::output_dir;
953 QString pfilewd = QFileInfo(parser.file).dirPath();
954 if(pfilewd.isEmpty())
955 include_roots << pfilewd;
956 if(Option::output_dir != QDir::currentDirPath())
957 include_roots << QDir::currentDirPath();
958 for(QStringList::Iterator it = include_roots.begin(); it != include_roots.end(); ++it) {
959 if(QFile::exists((*it) + QDir::separator() + file)) {
960 file = (*it) + QDir::separator() + file;
961 break;
962 }
824 } 963 }
825 } 964 }
826 965
966 if(Option::mkfile::do_preprocess) //nice to see this first..
967 fprintf(stderr, "#switching file %s(%s) - %s:%d\n", func.latin1(), file.latin1(),
968 parser.file.latin1(), parser.line_no);
827 debug_msg(1, "Project Parser: %s'ing file %s.", func.latin1(), file.latin1()); 969 debug_msg(1, "Project Parser: %s'ing file %s.", func.latin1(), file.latin1());
970 QString orig_file = file;
971 int di = file.findRev(Option::dir_sep);
972 QDir sunworkshop42workaround = QDir::current();
973 QString oldpwd = sunworkshop42workaround.currentDirPath();
974 if(di != -1) {
975 if(!QDir::setCurrent(file.left(file.findRev(Option::dir_sep)))) {
976 fprintf(stderr, "Cannot find directory: %s\n", file.left(di).latin1());
977 return FALSE;
978 }
979 file = file.right(file.length() - di - 1);
980 }
828 parser_info pi = parser; 981 parser_info pi = parser;
829 int sb = scope_block; 982 int sb = scope_block;
830 int sf = scope_flag; 983 int sf = scope_flag;
831 TestStatus sc = test_status; 984 TestStatus sc = test_status;
832 bool r = read(file.latin1(), place); 985 bool r = FALSE;
986 if(!seek_var.isNull()) {
987 QMap<QString, QStringList> tmp;
988 if((r = read(file.latin1(), tmp)))
989 place[seek_var] += tmp[seek_var];
990 } else {
991 r = read(file.latin1(), place);
992 }
833 if(r) 993 if(r)
834 vars["QMAKE_INTERNAL_INCLUDED_FILES"].append(file); 994 vars["QMAKE_INTERNAL_INCLUDED_FILES"].append(orig_file);
835 else 995 else
836 warn_msg(WarnParser, "%s:%d: Failure to include file %s.", 996 warn_msg(WarnParser, "%s:%d: Failure to include file %s.",
837 pi.file.latin1(), pi.line_no, file.latin1()); 997 pi.file.latin1(), pi.line_no, orig_file.latin1());
838 parser = pi; 998 parser = pi;
839 test_status = sc; 999 test_status = sc;
840 scope_flag = sf; 1000 scope_flag = sf;
841 scope_block = sb; 1001 scope_block = sb;
1002 QDir::setCurrent(oldpwd);
842 return r; 1003 return r;
843 } else if(func == "error" || func == "message") { 1004 } else if(func == "error" || func == "message") {
844 if(args.count() != 1) { 1005 if(args.count() != 1) {
845 fprintf(stderr, "%s:%d: %s(message) requires one argument.\n", parser.file.latin1(), 1006 fprintf(stderr, "%s:%d: %s(message) requires one argument.\n", parser.file.latin1(),
@@ -853,9 +1014,9 @@ QMakeProject::doProjectTest(const QString& func, QStringList args, QMap<QString,
853 msg.replace(QString("${QMAKE_LINE_NUMBER}"), QString::number(parser.line_no)); 1014 msg.replace(QString("${QMAKE_LINE_NUMBER}"), QString::number(parser.line_no));
854 msg.replace(QString("${QMAKE_DATE}"), QDateTime::currentDateTime().toString()); 1015 msg.replace(QString("${QMAKE_DATE}"), QDateTime::currentDateTime().toString());
855 doVariableReplace(msg, place); 1016 doVariableReplace(msg, place);
856 fixEnvVariables(msg); 1017 fixEnvVariables(msg);
857 printf("Project %s: %s\n", func.upper().latin1(), msg.latin1()); 1018 fprintf(stderr, "Project %s: %s\n", func.upper().latin1(), msg.latin1());
858 if(func == "message") 1019 if(func == "message")
859 return TRUE; 1020 return TRUE;
860 exit(2); 1021 exit(2);
861 } else { 1022 } else {
@@ -889,9 +1050,9 @@ QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringL
889 QString func = chk.left(lparen); 1050 QString func = chk.left(lparen);
890 test = doProjectTest(func, chk.mid(lparen+1, rparen - lparen - 1), place); 1051 test = doProjectTest(func, chk.mid(lparen+1, rparen - lparen - 1), place);
891 } 1052 }
892 } else { 1053 } else {
893 test = isActiveConfig(chk, TRUE); 1054 test = isActiveConfig(chk, TRUE, &place);
894 } 1055 }
895 if(invert_test) { 1056 if(invert_test) {
896 chk.prepend("!"); 1057 chk.prepend("!");
897 test = !test; 1058 test = !test;
@@ -910,45 +1071,59 @@ QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringL
910QString 1071QString
911QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &place) 1072QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &place)
912{ 1073{
913 for(int var_begin, var_last=0; (var_begin = str.find("$$", var_last)) != -1; var_last = var_begin) { 1074 for(int var_begin, var_last=0; (var_begin = str.find("$$", var_last)) != -1; var_last = var_begin) {
914 if(var_begin >= int( str.length() + 2 ) ) { 1075 if(var_begin >= (int)str.length() + 2) {
915 break; 1076 break;
916 } else if(var_begin != 0 && str[var_begin-1] == '\\') { 1077 } else if(var_begin != 0 && str[var_begin-1] == '\\') {
917 str.replace(var_begin-1, 1, ""); 1078 str.replace(var_begin-1, 1, "");
918 var_begin += 1; 1079 var_begin += 1;
919 continue; 1080 continue;
920 } 1081 }
921 1082
922 int var_incr = var_begin + 2; 1083 int var_incr = var_begin + 2;
923 bool in_braces = FALSE, as_env = FALSE; 1084 bool in_braces = FALSE, as_env = FALSE, as_prop = FALSE;
924 if(str[var_incr] == '{') { 1085 if(str[var_incr] == '{') {
925 in_braces = TRUE; 1086 in_braces = TRUE;
926 var_incr++; 1087 var_incr++;
927 while(var_incr < int( str.length() ) && 1088 while(var_incr < (int)str.length() &&
928 (str[var_incr] == ' ' || str[var_incr] == '\t' || str[var_incr] == '\n')) 1089 (str[var_incr] == ' ' || str[var_incr] == '\t' || str[var_incr] == '\n'))
929 var_incr++; 1090 var_incr++;
930 } 1091 }
931 if(str[var_incr] == '(') { 1092 if(str[var_incr] == '(') {
932 as_env = TRUE; 1093 as_env = TRUE;
933 var_incr++; 1094 var_incr++;
1095 } else if(str[var_incr] == '[') {
1096 as_prop = TRUE;
1097 var_incr++;
934 } 1098 }
935 QString val, args; 1099 QString val, args;
936 while(var_incr < int( str.length() ) && 1100 while(var_incr < (int)str.length() &&
937 (str[var_incr].isLetter() || str[var_incr].isNumber() || str[var_incr] == '.' || str[var_incr] == '_')) 1101 (str[var_incr].isLetter() || str[var_incr].isNumber() || str[var_incr] == '.' || str[var_incr] == '_'))
938 val += str[var_incr++]; 1102 val += str[var_incr++];
939 if(as_env) { 1103 if(as_env) {
940 if(str[var_incr] != ')') { 1104 if(str[var_incr] != ')') {
941 var_incr++; 1105 var_incr++;
942 warn_msg(WarnParser, "%s:%d: Unterminated env-variable replacement '%s' (%s)", 1106 warn_msg(WarnParser, "%s:%d: Unterminated env-variable replacement '%s' (%s)",
943 parser.file.latin1(), parser.line_no, 1107 parser.file.latin1(), parser.line_no,
1108 str.mid(var_begin, QMAX(var_incr - var_begin,
1109 (int)str.length())).latin1(), str.latin1());
1110 var_begin += var_incr;
1111 continue;
1112 }
1113 var_incr++;
1114 } else if(as_prop) {
1115 if(str[var_incr] != ']') {
1116 var_incr++;
1117 warn_msg(WarnParser, "%s:%d: Unterminated prop-variable replacement '%s' (%s)",
1118 parser.file.latin1(), parser.line_no,
944 str.mid(var_begin, QMAX(var_incr - var_begin, int(str.length()))).latin1(), str.latin1()); 1119 str.mid(var_begin, QMAX(var_incr - var_begin, int(str.length()))).latin1(), str.latin1());
945 var_begin += var_incr; 1120 var_begin += var_incr;
946 continue; 1121 continue;
947 } 1122 }
948 var_incr++; 1123 var_incr++;
949 } else if(str[var_incr] == '(') { //args 1124 } else if(str[var_incr] == '(') { //args
950 for(int parens = 0; var_incr < int( str.length() ); var_incr++) { 1125 for(int parens = 0; var_incr < (int)str.length(); var_incr++) {
951 if(str[var_incr] == '(') { 1126 if(str[var_incr] == '(') {
952 parens++; 1127 parens++;
953 if(parens == 1) 1128 if(parens == 1)
954 continue; 1129 continue;
@@ -961,13 +1136,14 @@ QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &
961 } 1136 }
962 args += str[var_incr]; 1137 args += str[var_incr];
963 } 1138 }
964 } 1139 }
965 if(var_incr > int( str.length() ) || (in_braces && str[var_incr] != '}')) { 1140 if(var_incr > (int)str.length() || (in_braces && str[var_incr] != '}')) {
966 var_incr++; 1141 var_incr++;
967 warn_msg(WarnParser, "%s:%d: Unterminated variable replacement '%s' (%s)", 1142 warn_msg(WarnParser, "%s:%d: Unterminated variable replacement '%s' (%s)",
968 parser.file.latin1(), parser.line_no, 1143 parser.file.latin1(), parser.line_no,
969 str.mid(var_begin, QMAX(var_incr - var_begin, int( str.length() ))).latin1(), str.latin1()); 1144 str.mid(var_begin, QMAX(var_incr - var_begin,
1145 (int)str.length())).latin1(), str.latin1());
970 var_begin += var_incr; 1146 var_begin += var_incr;
971 continue; 1147 continue;
972 } else if(in_braces) { 1148 } else if(in_braces) {
973 var_incr++; 1149 var_incr++;
@@ -975,41 +1151,116 @@ QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &
975 1151
976 QString replacement; 1152 QString replacement;
977 if(as_env) { 1153 if(as_env) {
978 replacement = getenv(val); 1154 replacement = getenv(val);
1155 } else if(as_prop) {
1156 if(prop)
1157 replacement = prop->value(val);
979 } else if(args.isEmpty()) { 1158 } else if(args.isEmpty()) {
980 if(val.left(1) == ".") 1159 if(val.left(1) == ".")
981 replacement = ""; 1160 replacement = "";
982 else if(val == "LITERAL_WHITESPACE") 1161 else if(val == "LITERAL_WHITESPACE")
983 replacement = "\t"; 1162 replacement = "\t";
1163 else if(val == "LITERAL_DOLLAR")
1164 replacement = "$";
1165 else if(val == "LITERAL_HASH")
1166 replacement = "#";
1167 else if(val == "PWD")
1168 replacement = QDir::currentDirPath();
1169 else if(val == "DIR_SEPARATOR")
1170 replacement = Option::dir_sep;
984 else 1171 else
985 replacement = place[varMap(val)].join(" "); 1172 replacement = place[varMap(val)].join(" ");
986 } else { 1173 } else {
987 QStringList arg_list = split_arg_list(args); 1174 QStringList arg_list = split_arg_list(doVariableReplace(args, place));
988 for(QStringList::Iterator arit = arg_list.begin(); arit != arg_list.end(); ++arit) {
989 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space
990 doVariableReplace((*arit), place);
991 }
992 debug_msg(1, "Running function: %s( %s )", val.latin1(), arg_list.join("::").latin1()); 1175 debug_msg(1, "Running function: %s( %s )", val.latin1(), arg_list.join("::").latin1());
993 if(val.lower() == "member") { 1176 if(val.lower() == "member") {
994 if(arg_list.count() < 1 || arg_list.count() > 2) { 1177 if(arg_list.count() < 1 || arg_list.count() > 3) {
995 fprintf(stderr, "%s:%d: member(var, place) requires two arguments.\n", 1178 fprintf(stderr, "%s:%d: member(var, start, end) requires three arguments.\n",
996 parser.file.latin1(), parser.line_no); 1179 parser.file.latin1(), parser.line_no);
997 } else { 1180 } else {
998 uint pos = 0;
999 if(arg_list.count() == 2)
1000 pos = arg_list[1].toInt();
1001 const QStringList &var = place[varMap(arg_list.first())]; 1181 const QStringList &var = place[varMap(arg_list.first())];
1002 if(var.count() >= pos) 1182 int start = 0;
1003 replacement = var[pos]; 1183 if(arg_list.count() >= 2)
1184 start = arg_list[1].toInt();
1185 if(start < 0)
1186 start += int(var.count());
1187 int end = start;
1188 if(arg_list.count() == 3)
1189 end = arg_list[2].toInt();
1190 if(end < 0)
1191 end += int(var.count());
1192 if(end < start)
1193 end = start;
1194 for(int i = start; i <= end && (int)var.count() >= i; i++) {
1195 if(!replacement.isEmpty())
1196 replacement += " ";
1197 replacement += var[i];
1198 }
1199 }
1200 } else if(val.lower() == "fromfile") {
1201 if(arg_list.count() != 2) {
1202 fprintf(stderr, "%s:%d: fromfile(file, variable) requires two arguments.\n",
1203 parser.file.latin1(), parser.line_no);
1204 } else {
1205 QString file = arg_list[0];
1206 file = Option::fixPathToLocalOS(file);
1207 file.replace("\"", "");
1208
1209 if(QDir::isRelativePath(file)) {
1210 QStringList include_roots;
1211 include_roots << Option::output_dir;
1212 QString pfilewd = QFileInfo(parser.file).dirPath();
1213 if(pfilewd.isEmpty())
1214 include_roots << pfilewd;
1215 if(Option::output_dir != QDir::currentDirPath())
1216 include_roots << QDir::currentDirPath();
1217 for(QStringList::Iterator it = include_roots.begin(); it != include_roots.end(); ++it) {
1218 if(QFile::exists((*it) + QDir::separator() + file)) {
1219 file = (*it) + QDir::separator() + file;
1220 break;
1221 }
1222 }
1223 }
1224 QString orig_file = file;
1225 int di = file.findRev(Option::dir_sep);
1226 QDir sunworkshop42workaround = QDir::current();
1227 QString oldpwd = sunworkshop42workaround.currentDirPath();
1228 if(di != -1 && QDir::setCurrent(file.left(file.findRev(Option::dir_sep))))
1229 file = file.right(file.length() - di - 1);
1230 parser_info pi = parser;
1231 int sb = scope_block;
1232 int sf = scope_flag;
1233 TestStatus sc = test_status;
1234 QMap<QString, QStringList> tmp;
1235 bool r = read(file.latin1(), tmp);
1236 if(r) {
1237 replacement = tmp[arg_list[1]].join(" ");
1238 vars["QMAKE_INTERNAL_INCLUDED_FILES"].append(orig_file);
1239 } else {
1240 warn_msg(WarnParser, "%s:%d: Failure to include file %s.",
1241 pi.file.latin1(), pi.line_no, orig_file.latin1());
1242 }
1243 parser = pi;
1244 test_status = sc;
1245 scope_flag = sf;
1246 scope_block = sb;
1247 QDir::setCurrent(oldpwd);
1248 }
1249 } else if(val.lower() == "eval") {
1250 for(QStringList::ConstIterator arg_it = arg_list.begin();
1251 arg_it != arg_list.end(); ++arg_it) {
1252 if(!replacement.isEmpty())
1253 replacement += " ";
1254 replacement += place[(*arg_it)].join(" ");
1004 } 1255 }
1005 } else if(val.lower() == "list") { 1256 } else if(val.lower() == "list") {
1006 static int x = 0; 1257 static int x = 0;
1007 replacement.sprintf(".QMAKE_INTERNAL_TMP_VAR_%d", x++); 1258 replacement.sprintf(".QMAKE_INTERNAL_TMP_VAR_%d", x++);
1008 QStringList &lst = (*((QMap<QString, QStringList>*)&place))[replacement]; 1259 QStringList &lst = (*((QMap<QString, QStringList>*)&place))[replacement];
1009 lst.clear(); 1260 lst.clear();
1010 for(QStringList::ConstIterator arg_it = arg_list.begin(); 1261 for(QStringList::ConstIterator arg_it = arg_list.begin();
1011 arg_it != arg_list.end(); ++arg_it) 1262 arg_it != arg_list.end(); ++arg_it)
1012 lst += split_value_list((*arg_it)); 1263 lst += split_value_list((*arg_it));
1013 } else if(val.lower() == "join") { 1264 } else if(val.lower() == "join") {
1014 if(arg_list.count() < 1 || arg_list.count() > 4) { 1265 if(arg_list.count() < 1 || arg_list.count() > 4) {
1015 fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four" 1266 fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four"
@@ -1025,8 +1276,26 @@ QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &
1025 const QStringList &var = place[varMap(arg_list.first())]; 1276 const QStringList &var = place[varMap(arg_list.first())];
1026 if(!var.isEmpty()) 1277 if(!var.isEmpty())
1027 replacement = before + var.join(glue) + after; 1278 replacement = before + var.join(glue) + after;
1028 } 1279 }
1280 } else if(val.lower() == "split") {
1281 if(arg_list.count() < 2 || arg_list.count() > 3) {
1282 fprintf(stderr, "%s:%d split(var, sep, join) requires three arguments\n",
1283 parser.file.latin1(), parser.line_no);
1284 } else {
1285 QString sep = arg_list[1], join = " ";
1286 if(arg_list.count() == 3)
1287 join = arg_list[2];
1288 QStringList var = place[varMap(arg_list.first())];
1289 for(QStringList::Iterator vit = var.begin(); vit != var.end(); ++vit) {
1290 QStringList lst = QStringList::split(sep, (*vit));
1291 for(QStringList::Iterator spltit = lst.begin(); spltit != lst.end(); ++spltit) {
1292 if(!replacement.isEmpty())
1293 replacement += join;
1294 replacement += (*spltit);
1295 }
1296 }
1297 }
1029 } else if(val.lower() == "find") { 1298 } else if(val.lower() == "find") {
1030 if(arg_list.count() != 2) { 1299 if(arg_list.count() != 2) {
1031 fprintf(stderr, "%s:%d find(var, str) requires two arguments\n", 1300 fprintf(stderr, "%s:%d find(var, str) requires two arguments\n",
1032 parser.file.latin1(), parser.line_no); 1301 parser.file.latin1(), parser.line_no);
@@ -1049,9 +1318,9 @@ QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &
1049 } else { 1318 } else {
1050 char buff[256]; 1319 char buff[256];
1051 FILE *proc = QT_POPEN(arg_list.join(" ").latin1(), "r"); 1320 FILE *proc = QT_POPEN(arg_list.join(" ").latin1(), "r");
1052 while(proc && !feof(proc)) { 1321 while(proc && !feof(proc)) {
1053 int read_in = fread(buff, 1, 255, proc); 1322 int read_in = int(fread(buff, 1, 255, proc));
1054 if(!read_in) 1323 if(!read_in)
1055 break; 1324 break;
1056 for(int i = 0; i < read_in; i++) { 1325 for(int i = 0; i < read_in; i++) {
1057 if(buff[i] == '\n' || buff[i] == '\t') 1326 if(buff[i] == '\n' || buff[i] == '\t')
@@ -1060,8 +1329,53 @@ QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &
1060 buff[read_in] = '\0'; 1329 buff[read_in] = '\0';
1061 replacement += buff; 1330 replacement += buff;
1062 } 1331 }
1063 } 1332 }
1333 } else if(val.lower() == "files") {
1334 if(arg_list.count() != 1) {
1335 fprintf(stderr, "%s:%d files(pattern) requires one argument\n",
1336 parser.file.latin1(), parser.line_no);
1337 } else {
1338 QString dir, regex = arg_list[0];
1339 regex = Option::fixPathToLocalOS(regex);
1340 regex.replace("\"", "");
1341 if(regex.findRev(QDir::separator()) != -1) {
1342 dir = regex.left(regex.findRev(QDir::separator()) + 1);
1343 regex = regex.right(regex.length() - dir.length());
1344 }
1345 QDir d(dir, regex);
1346 for(int i = 0; i < (int)d.count(); i++) {
1347 if(!replacement.isEmpty())
1348 replacement += " ";
1349 replacement += dir + d[i];
1350 }
1351 }
1352 } else if(val.lower() == "prompt") {
1353 if(arg_list.count() != 1) {
1354 fprintf(stderr, "%s:%d prompt(question) requires one argument\n",
1355 parser.file.latin1(), parser.line_no);
1356 } else if(projectFile() == "-") {
1357 fprintf(stderr, "%s:%d prompt(question) cannot be used when '-o -' is used.\n",
1358 parser.file.latin1(), parser.line_no);
1359 } else {
1360 QString msg = arg_list.first();
1361 if((msg.startsWith("\"") || msg.startsWith("'")) && msg.endsWith(msg.left(1)))
1362 msg = msg.mid(1, msg.length()-2);
1363 msg.replace(QString("${QMAKE_FILE}"), parser.file.latin1());
1364 msg.replace(QString("${QMAKE_LINE_NUMBER}"), QString::number(parser.line_no));
1365 msg.replace(QString("${QMAKE_DATE}"), QDateTime::currentDateTime().toString());
1366 doVariableReplace(msg, place);
1367 fixEnvVariables(msg);
1368 if(!msg.endsWith("?"))
1369 msg += "?";
1370 fprintf(stderr, "Project %s: %s ", val.upper().latin1(), msg.latin1());
1371
1372 QFile qfile;
1373 if(qfile.open(IO_ReadOnly, stdin)) {
1374 QTextStream t(&qfile);
1375 replacement = t.readLine();
1376 }
1377 }
1064 } else { 1378 } else {
1065 fprintf(stderr, "%s:%d: Unknown replace function: %s\n", 1379 fprintf(stderr, "%s:%d: Unknown replace function: %s\n",
1066 parser.file.latin1(), parser.line_no, val.latin1()); 1380 parser.file.latin1(), parser.line_no, val.latin1());
1067 } 1381 }