summaryrefslogtreecommitdiff
path: root/qmake/project.cpp
Unidiff
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,1077 +1,1391 @@
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.
15** 13**
16** This file may be distributed and/or modified under the terms of the 14** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software 15** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the 16** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file. 17** packaging of this file.
20** 18**
21** Licensees holding valid Qt Enterprise Edition licenses may use this 19** Licensees holding valid Qt Enterprise Edition licenses may use this
22** file in accordance with the Qt Commercial License Agreement provided 20** file in accordance with the Qt Commercial License Agreement provided
23** with the Software. 21** with the Software.
24** 22**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 23** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 24** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27** 25**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for 26** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements. 27** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information. 28** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information. 29** See http://www.trolltech.com/gpl/ for GPL licensing information.
32** 30**
33** Contact info@trolltech.com if any conditions of this licensing are 31** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you. 32** not clear to you.
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>
43#include <qtextstream.h> 42#include <qtextstream.h>
44#include <qvaluestack.h> 43#include <qvaluestack.h>
45#ifdef Q_OS_UNIX 44#ifdef Q_OS_UNIX
46# include <unistd.h> 45# include <unistd.h>
47#endif 46#endif
48#include <stdio.h> 47#include <stdio.h>
49#include <stdlib.h> 48#include <stdlib.h>
50 49
51#ifdef Q_OS_WIN32 50#ifdef Q_OS_WIN32
52#define QT_POPEN _popen 51#define QT_POPEN _popen
53#else 52#else
54#define QT_POPEN popen 53#define QT_POPEN popen
55#endif 54#endif
56 55
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;
138 213
139 if(s.stripWhiteSpace().left(1) == "}") { 214 if(s.stripWhiteSpace().left(1) == "}") {
140 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(), 215 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(),
141 parser.line_no, scope_block); 216 parser.line_no, scope_block);
142 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek); 217 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek);
143 scope_block--; 218 scope_block--;
144 s = s.mid(1).stripWhiteSpace(); 219 s = s.mid(1).stripWhiteSpace();
145 if(s.isEmpty()) 220 if(s.isEmpty())
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;
155 } 230 }
156 231
157 QString scope, var, op; 232 QString scope, var, op;
158 QStringList val; 233 QStringList val;
159#define SKIP_WS(d) while(*d && (*d == ' ' || *d == '\t')) d++ 234#define SKIP_WS(d) while(*d && (*d == ' ' || *d == '\t')) d++
160 const char *d = s.latin1(); 235 const char *d = s.latin1();
161 SKIP_WS(d); 236 SKIP_WS(d);
162 bool scope_failed = FALSE, else_line = FALSE, or_op=FALSE; 237 bool scope_failed = FALSE, else_line = FALSE, or_op=FALSE;
163 int parens = 0, scope_count=0; 238 int parens = 0, scope_count=0;
164 while(*d) { 239 while(*d) {
165 if(!parens) { 240 if(!parens) {
166 if(*d == '=') 241 if(*d == '=')
167 break; 242 break;
168 if(*d == '+' || *d == '-' || *d == '*' || *d == '~') { 243 if(*d == '+' || *d == '-' || *d == '*' || *d == '~') {
169 if(*(d+1) == '=') { 244 if(*(d+1) == '=') {
170 break; 245 break;
171 } else if(*(d+1) == ' ') { 246 } else if(*(d+1) == ' ') {
172 const char *k = d + 1; 247 const char *k = d + 1;
173 SKIP_WS(k); 248 SKIP_WS(k);
174 if(*k == '=') { 249 if(*k == '=') {
175 QString msg; 250 QString msg;
176 qmake_error_msg(*d + "must be followed immediately by ="); 251 qmake_error_msg(*d + "must be followed immediately by =");
177 return FALSE; 252 return FALSE;
178 } 253 }
179 } 254 }
180 } 255 }
181 } 256 }
182 257
183 if ( *d == '(' ) 258 if ( *d == '(' )
184 ++parens; 259 ++parens;
185 else if ( *d == ')' ) 260 else if ( *d == ')' )
186 --parens; 261 --parens;
187 262
188 if(!parens && (*d == ':' || *d == '{' || *d == ')' || *d == '|')) { 263 if(!parens && (*d == ':' || *d == '{' || *d == ')' || *d == '|')) {
189 scope_count++; 264 scope_count++;
190 scope = var.stripWhiteSpace(); 265 scope = var.stripWhiteSpace();
191 if ( *d == ')' ) 266 if ( *d == ')' )
192 scope += *d; /* need this */ 267 scope += *d; /* need this */
193 var = ""; 268 var = "";
194 269
195 bool test = scope_failed; 270 bool test = scope_failed;
196 if(scope.lower() == "else") { 271 if(scope.lower() == "else") {
197 if(scope_count != 1 || test_status == TestNone) { 272 if(scope_count != 1 || test_status == TestNone) {
198 qmake_error_msg("Unexpected " + scope + " ('" + s + "')"); 273 qmake_error_msg("Unexpected " + scope + " ('" + s + "')");
199 return FALSE; 274 return FALSE;
200 } 275 }
201 else_line = TRUE; 276 else_line = TRUE;
202 test = (test_status == TestSeek); 277 test = (test_status == TestSeek);
203 debug_msg(1, "Project Parser: %s:%d : Else%s %s.", parser.file.latin1(), parser.line_no, 278 debug_msg(1, "Project Parser: %s:%d : Else%s %s.", parser.file.latin1(), parser.line_no,
204 scope == "else" ? "" : QString(" (" + scope + ")").latin1(), 279 scope == "else" ? "" : QString(" (" + scope + ")").latin1(),
205 test ? "considered" : "excluded"); 280 test ? "considered" : "excluded");
206 } else { 281 } else {
207 QString comp_scope = scope; 282 QString comp_scope = scope;
208 bool invert_test = (comp_scope.left(1) == "!"); 283 bool invert_test = (comp_scope.left(1) == "!");
209 if(invert_test) 284 if(invert_test)
210 comp_scope = comp_scope.right(comp_scope.length()-1); 285 comp_scope = comp_scope.right(comp_scope.length()-1);
211 int lparen = comp_scope.find('('); 286 int lparen = comp_scope.find('(');
212 if(or_op || !scope_failed) { 287 if(or_op || !scope_failed) {
213 if(lparen != -1) { /* if there is an lparen in the scope, it IS a function */ 288 if(lparen != -1) { /* if there is an lparen in the scope, it IS a function */
214 int rparen = comp_scope.findRev(')'); 289 int rparen = comp_scope.findRev(')');
215 if(rparen == -1) { 290 if(rparen == -1) {
216 QCString error; 291 QCString error;
217 error.sprintf("Function missing right paren: %s ('%s')", 292 error.sprintf("Function missing right paren: %s ('%s')",
218 comp_scope.latin1(), s.latin1()); 293 comp_scope.latin1(), s.latin1());
219 qmake_error_msg(error); 294 qmake_error_msg(error);
220 return FALSE; 295 return FALSE;
221 } 296 }
222 QString func = comp_scope.left(lparen); 297 QString func = comp_scope.left(lparen);
223 test = doProjectTest(func, comp_scope.mid(lparen+1, rparen - lparen - 1), place); 298 test = doProjectTest(func, comp_scope.mid(lparen+1, rparen - lparen - 1), place);
224 if ( *d == ')' && !*(d+1) ) { 299 if ( *d == ')' && !*(d+1) ) {
225 if(invert_test) 300 if(invert_test)
226 test = !test; 301 test = !test;
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 }
236 } 311 }
237 if(!test && !scope_failed) 312 if(!test && !scope_failed)
238 debug_msg(1, "Project Parser: %s:%d : Test (%s) failed.", parser.file.latin1(), 313 debug_msg(1, "Project Parser: %s:%d : Test (%s) failed.", parser.file.latin1(),
239 parser.line_no, scope.latin1()); 314 parser.line_no, scope.latin1());
240 if(test == or_op) 315 if(test == or_op)
241 scope_failed = !test; 316 scope_failed = !test;
242 or_op = (*d == '|'); 317 or_op = (*d == '|');
243 if(*d == '{') { /* scoping block */ 318 if(*d == '{') { /* scoping block */
244 if(!scope_failed) 319 if(!scope_failed)
245 scope_flag |= (0x01 << (++scope_block)); 320 scope_flag |= (0x01 << (++scope_block));
246 else 321 else
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 */
274 int rbraces = vals.contains('}'), lbraces = vals.contains('{'); 359 int rbraces = vals.contains('}'), lbraces = vals.contains('{');
275 if(scope_block && rbraces - lbraces == 1) { 360 if(scope_block && rbraces - lbraces == 1) {
276 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(), 361 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(),
277 parser.line_no, scope_block); 362 parser.line_no, scope_block);
278 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek); 363 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek);
279 scope_block--; 364 scope_block--;
280 vals.truncate(vals.length()-1); 365 vals.truncate(vals.length()-1);
281 } else if(rbraces != lbraces) { 366 } else if(rbraces != lbraces) {
282 warn_msg(WarnParser, "Possible braces mismatch {%s} %s:%d", 367 warn_msg(WarnParser, "Possible braces mismatch {%s} %s:%d",
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 */
301 QStringList vallist = split_value_list(vals, (var == "DEPENDPATH" || var == "INCLUDEPATH")); 385 QStringList vallist = split_value_list(vals, (var == "DEPENDPATH" || var == "INCLUDEPATH"));
302 if(!vallist.grep("=").isEmpty()) 386 if(!vallist.grep("=").isEmpty())
303 warn_msg(WarnParser, "Detected possible line continuation: {%s} %s:%d", 387 warn_msg(WarnParser, "Detected possible line continuation: {%s} %s:%d",
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) {
313 qmake_error_msg("~= operator only accepts one right hand paramater ('" + 397 qmake_error_msg("~= operator only accepts one right hand paramater ('" +
314 s + "')"); 398 s + "')");
315 return FALSE; 399 return FALSE;
316 } 400 }
317 QString val(vallist.first()); 401 QString val(vallist.first());
318 if(val.length() < 4 || val.at(0) != 's') { 402 if(val.length() < 4 || val.at(0) != 's') {
319 qmake_error_msg("~= operator only can handle s/// function ('" + 403 qmake_error_msg("~= operator only can handle s/// function ('" +
320 s + "')"); 404 s + "')");
321 return FALSE; 405 return FALSE;
322 } 406 }
323 QChar sep = val.at(1); 407 QChar sep = val.at(1);
324 QStringList func = QStringList::split(sep, val, TRUE); 408 QStringList func = QStringList::split(sep, val, TRUE);
325 if(func.count() < 3 || func.count() > 4) { 409 if(func.count() < 3 || func.count() > 4) {
326 qmake_error_msg("~= operator only can handle s/// function ('" + 410 qmake_error_msg("~= operator only can handle s/// function ('" +
327 s + "')"); 411 s + "')");
328 return FALSE; 412 return FALSE;
329 } 413 }
330 bool global = FALSE, case_sense = TRUE; 414 bool global = FALSE, case_sense = TRUE;
331 if(func.count() == 4) { 415 if(func.count() == 4) {
332 global = func[3].find('g') != -1; 416 global = func[3].find('g') != -1;
333 case_sense = func[3].find('i') == -1; 417 case_sense = func[3].find('i') == -1;
334 } 418 }
335 QRegExp regexp(func[1], case_sense); 419 QRegExp regexp(func[1], case_sense);
336 for(QStringList::Iterator varit = varlist.begin(); 420 for(QStringList::Iterator varit = varlist.begin();
337 varit != varlist.end(); ++varit) { 421 varit != varlist.end(); ++varit) {
338 if((*varit).contains(regexp)) { 422 if((*varit).contains(regexp)) {
339 (*varit) = (*varit).replace(regexp, func[2]); 423 (*varit) = (*varit).replace(regexp, func[2]);
340 if(!global) 424 if(!global)
341 break; 425 break;
342 } 426 }
343 } 427 }
344 } else { 428 } else {
345 if(op == "=") { 429 if(op == "=") {
346 if(!varlist.isEmpty()) 430 if(!varlist.isEmpty())
347 warn_msg(WarnParser, "Operator=(%s) clears variables previously set: %s:%d", 431 warn_msg(WarnParser, "Operator=(%s) clears variables previously set: %s:%d",
348 var.latin1(), parser.file.latin1(), parser.line_no); 432 var.latin1(), parser.file.latin1(), parser.line_no);
349 varlist.clear(); 433 varlist.clear();
350 } 434 }
351 for(QStringList::Iterator valit = vallist.begin(); 435 for(QStringList::Iterator valit = vallist.begin();
352 valit != vallist.end(); ++valit) { 436 valit != vallist.end(); ++valit) {
353 if((*valit).isEmpty()) 437 if((*valit).isEmpty())
354 continue; 438 continue;
355 if((op == "*=" && !(*varlist.find((*valit)))) || 439 if((op == "*=" && !(*varlist.find((*valit)))) ||
356 op == "=" || op == "+=") 440 op == "=" || op == "+=")
357 varlist.append((*valit)); 441 varlist.append((*valit));
358 else if(op == "-=") 442 else if(op == "-=")
359 varlist.remove((*valit)); 443 varlist.remove((*valit));
360 } 444 }
361 } 445 }
362 if(var == "REQUIRES") /* special case to get communicated to backends! */ 446 if(var == "REQUIRES") /* special case to get communicated to backends! */
363 doProjectCheckReqs(vallist, place); 447 doProjectCheckReqs(vallist, place);
364 448
365 return TRUE; 449 return TRUE;
366} 450}
367 451
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;
380 QFile qfile; 461 QFile qfile;
381 if(!strcmp(filename, "-")) { 462 if(!strcmp(filename, "-")) {
382 qfile.setName(""); 463 qfile.setName("");
383 ret = qfile.open(IO_ReadOnly, stdin); 464 ret = qfile.open(IO_ReadOnly, stdin);
384 using_stdin = TRUE; 465 using_stdin = TRUE;
385 } else { 466 } else {
386 qfile.setName(filename); 467 qfile.setName(filename);
387 ret = qfile.open(IO_ReadOnly); 468 ret = qfile.open(IO_ReadOnly);
388 } 469 }
389 if ( ret ) { 470 if ( ret ) {
390 QTextStream t( &qfile ); 471 QTextStream t( &qfile );
391 QString s, line; 472 QString s, line;
392 parser.file = filename; 473 parser.file = filename;
393 parser.line_no = 0; 474 parser.line_no = 0;
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())
410 s += line; 492 s += line;
411 if(!s.isEmpty()) { 493 if(!s.isEmpty()) {
412 if(!(ret = parse(s, place))) 494 if(!(ret = parse(s, place)))
413 break; 495 break;
414 s = ""; 496 s = "";
415 } 497 }
416 } 498 }
417 } 499 }
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"))) {
448 dir = dir.left(dir.findRev(QDir::separator())); 532 dir = dir.left(dir.findRev(QDir::separator()));
449 if(dir.isEmpty() || dir.find(QDir::separator()) == -1) { 533 if(dir.isEmpty() || dir.find(QDir::separator()) == -1) {
450 Option::mkfile::cachefile = ""; 534 Option::mkfile::cachefile = "";
451 break; 535 break;
452 } 536 }
453 if(Option::mkfile::cachefile_depth == -1) 537 if(Option::mkfile::cachefile_depth == -1)
454 Option::mkfile::cachefile_depth = 1; 538 Option::mkfile::cachefile_depth = 1;
455 else 539 else
456 Option::mkfile::cachefile_depth++; 540 Option::mkfile::cachefile_depth++;
457 } 541 }
458 } 542 }
459 if(!Option::mkfile::cachefile.isEmpty()) { 543 if(!Option::mkfile::cachefile.isEmpty()) {
460 read(Option::mkfile::cachefile, cache); 544 read(Option::mkfile::cachefile, cache);
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
559 QStringList &templ = vars["TEMPLATE"]; 654 QStringList &templ = vars["TEMPLATE"];
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);
571 // fi.baseName(); 665 // fi.baseName();
572 QString tmp = pfile; 666 QString tmp = pfile;
573 if(tmp.findRev('/') != -1) 667 if(tmp.findRev('/') != -1)
574 tmp = tmp.right( tmp.length() - tmp.findRev('/') - 1 ); 668 tmp = tmp.right( tmp.length() - tmp.findRev('/') - 1 );
575 if(tmp.findRev('.') != -1) 669 if(tmp.findRev('.') != -1)
576 tmp = tmp.left(tmp.findRev('.')); 670 tmp = tmp.left(tmp.findRev('.'));
577 vars["TARGET"].append(tmp); 671 vars["TARGET"].append(tmp);
578 } 672 }
579 673
580 QString test_version = getenv("QTESTVERSION"); 674 QString test_version = getenv("QTESTVERSION");
581 if (!test_version.isEmpty()) { 675 if (!test_version.isEmpty()) {
582 QString s = vars["TARGET"].first(); 676 QString s = vars["TARGET"].first();
583 if (s == "qt" || s == "qt-mt" || s == "qte" || s == "qte-mt") { 677 if (s == "qt" || s == "qt-mt" || s == "qte" || s == "qte-mt") {
584 QString &ver = vars["VERSION"].first(); 678 QString &ver = vars["VERSION"].first();
585 // fprintf(stderr,"Current QT version number: " + ver + "\n"); 679 // fprintf(stderr,"Current QT version number: " + ver + "\n");
586 if (ver != "" && ver != test_version) { 680 if (ver != "" && ver != test_version) {
587 ver = test_version; 681 ver = test_version;
588 fprintf(stderr,"Changed QT version number to " + test_version + "!\n"); 682 fprintf(stderr,"Changed QT version number to " + test_version + "!\n");
589 } 683 }
590 } 684 }
591 } 685 }
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
601 if((Option::target_mode == Option::TARG_MACX_MODE || Option::target_mode == Option::TARG_QNX6_MODE || 695 if((Option::target_mode == Option::TARG_MACX_MODE || Option::target_mode == Option::TARG_QNX6_MODE ||
602 Option::target_mode == Option::TARG_UNIX_MODE) && x == "unix") 696 Option::target_mode == Option::TARG_UNIX_MODE) && x == "unix")
603 return TRUE; 697 return TRUE;
604 else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx") 698 else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx")
605 return TRUE; 699 return TRUE;
606 else if(Option::target_mode == Option::TARG_QNX6_MODE && x == "qnx6") 700 else if(Option::target_mode == Option::TARG_QNX6_MODE && x == "qnx6")
607 return TRUE; 701 return TRUE;
608 else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9") 702 else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9")
609 return TRUE; 703 return TRUE;
610 else if((Option::target_mode == Option::TARG_MAC9_MODE || Option::target_mode == Option::TARG_MACX_MODE) && 704 else if((Option::target_mode == Option::TARG_MAC9_MODE || Option::target_mode == Option::TARG_MACX_MODE) &&
611 x == "mac") 705 x == "mac")
612 return TRUE; 706 return TRUE;
613 else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32") 707 else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32")
614 return TRUE; 708 return TRUE;
615 709
616 710
617 QRegExp re(x, FALSE, TRUE); 711 QRegExp re(x, FALSE, TRUE);
618 QString spec = Option::mkfile::qmakespec.right(Option::mkfile::qmakespec.length() - 712 QString spec = Option::mkfile::qmakespec.right(Option::mkfile::qmakespec.length() -
619 (Option::mkfile::qmakespec.findRev(QDir::separator())+1)); 713 (Option::mkfile::qmakespec.findRev(QDir::separator())+1));
620 if((regex && re.exactMatch(spec)) || (!regex && spec == x)) 714 if((regex && re.exactMatch(spec)) || (!regex && spec == x))
621 return TRUE; 715 return TRUE;
622#ifdef Q_OS_UNIX 716#ifdef Q_OS_UNIX
623 else if(spec == "default") { 717 else if(spec == "default") {
624 static char *buffer = NULL; 718 static char *buffer = NULL;
625 if(!buffer) 719 if(!buffer)
626 buffer = (char *)malloc(1024); 720 buffer = (char *)malloc(1024);
627 int l = readlink(Option::mkfile::qmakespec, buffer, 1024); 721 int l = readlink(Option::mkfile::qmakespec, buffer, 1024);
628 if(l != -1) { 722 if(l != -1) {
629 buffer[l] = '\0'; 723 buffer[l] = '\0';
630 QString r = buffer; 724 QString r = buffer;
631 if(r.findRev('/') != -1) 725 if(r.findRev('/') != -1)
632 r = r.mid(r.findRev('/') + 1); 726 r = r.mid(r.findRev('/') + 1);
633 if((regex && re.exactMatch(r)) || (!regex && r == x)) 727 if((regex && re.exactMatch(r)) || (!regex && r == x))
634 return TRUE; 728 return TRUE;
635 } 729 }
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;
645 } 739 }
646 return FALSE; 740 return FALSE;
647} 741}
648 742
649bool 743bool
650QMakeProject::doProjectTest(const QString& func, const QString &params, QMap<QString, QStringList> &place) 744QMakeProject::doProjectTest(const QString& func, const QString &params, QMap<QString, QStringList> &place)
651{ 745{
652 QStringList args = split_arg_list(params); 746 QStringList args = split_arg_list(params);
653 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) { 747 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) {
654 QString tmp = (*arit).stripWhiteSpace(); 748 QString tmp = (*arit).stripWhiteSpace();
655 if((tmp[0] == '\'' || tmp[0] == '"') && tmp.right(1) == tmp.left(1)) 749 if((tmp[0] == '\'' || tmp[0] == '"') && tmp.right(1) == tmp.left(1))
656 tmp = tmp.mid(1, tmp.length() - 2); 750 tmp = tmp.mid(1, tmp.length() - 2);
657 } 751 }
658 return doProjectTest(func.stripWhiteSpace(), args, place); 752 return doProjectTest(func.stripWhiteSpace(), args, place);
659} 753}
660 754
661bool 755bool
662QMakeProject::doProjectTest(const QString& func, QStringList args, QMap<QString, QStringList> &place) 756QMakeProject::doProjectTest(const QString& func, QStringList args, QMap<QString, QStringList> &place)
663{ 757{
664 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) { 758 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) {
665 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space 759 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space
666 doVariableReplace((*arit), place); 760 doVariableReplace((*arit), place);
667 } 761 }
668 debug_msg(1, "Running project test: %s( %s )", func.latin1(), args.join("::").latin1()); 762 debug_msg(1, "Running project test: %s( %s )", func.latin1(), args.join("::").latin1());
669 763
670 if(func == "requires") { 764 if(func == "requires") {
671 return doProjectCheckReqs(args, place); 765 return doProjectCheckReqs(args, place);
672 } else if(func == "equals") { 766 } else if(func == "equals") {
673 if(args.count() != 2) { 767 if(args.count() != 2) {
674 fprintf(stderr, "%s:%d: equals(variable, value) requires two arguments.\n", parser.file.latin1(), 768 fprintf(stderr, "%s:%d: equals(variable, value) requires two arguments.\n", parser.file.latin1(),
675 parser.line_no); 769 parser.line_no);
676 return FALSE; 770 return FALSE;
677 } 771 }
678 QString value = args[1]; 772 QString value = args[1];
679 if((value.left(1) == "\"" || value.left(1) == "'") && value.right(1) == value.left(1)) 773 if((value.left(1) == "\"" || value.left(1) == "'") && value.right(1) == value.left(1))
680 value = value.mid(1, value.length()-2); 774 value = value.mid(1, value.length()-2);
681 return vars[args[0]].join(" ") == value; 775 return vars[args[0]].join(" ") == value;
682 } else if(func == "exists") { 776 } else if(func == "exists") {
683 if(args.count() != 1) { 777 if(args.count() != 1) {
684 fprintf(stderr, "%s:%d: exists(file) requires one argument.\n", parser.file.latin1(), 778 fprintf(stderr, "%s:%d: exists(file) requires one argument.\n", parser.file.latin1(),
685 parser.line_no); 779 parser.line_no);
686 return FALSE; 780 return FALSE;
687 } 781 }
688 QString file = args.first(); 782 QString file = args.first();
689 file = Option::fixPathToLocalOS(file); 783 file = Option::fixPathToLocalOS(file);
690 doVariableReplace(file, place); 784 doVariableReplace(file, place);
691 785
692 if(QFile::exists(file)) 786 if(QFile::exists(file))
693 return TRUE; 787 return TRUE;
694 //regular expression I guess 788 //regular expression I guess
695 QString dirstr = QDir::currentDirPath(); 789 QString dirstr = QDir::currentDirPath();
696 int slsh = file.findRev(Option::dir_sep); 790 int slsh = file.findRev(Option::dir_sep);
697 if(slsh != -1) { 791 if(slsh != -1) {
698 dirstr = file.left(slsh+1); 792 dirstr = file.left(slsh+1);
699 file = file.right(file.length() - slsh - 1); 793 file = file.right(file.length() - slsh - 1);
700 } 794 }
701 QDir dir(dirstr, file); 795 QDir dir(dirstr, file);
702 return dir.count() != 0; 796 return dir.count() != 0;
703 } else if(func == "system") { 797 } else if(func == "system") {
704 if(args.count() != 1) { 798 if(args.count() != 1) {
705 fprintf(stderr, "%s:%d: system(exec) requires one argument.\n", parser.file.latin1(), 799 fprintf(stderr, "%s:%d: system(exec) requires one argument.\n", parser.file.latin1(),
706 parser.line_no); 800 parser.line_no);
707 return FALSE; 801 return FALSE;
708 } 802 }
709 return system(args.first().latin1()) == 0; 803 return system(args.first().latin1()) == 0;
710 } else if(func == "contains") { 804 } else if(func == "contains") {
711 if(args.count() != 2) { 805 if(args.count() != 2) {
712 fprintf(stderr, "%s:%d: contains(var, val) requires two arguments.\n", parser.file.latin1(), 806 fprintf(stderr, "%s:%d: contains(var, val) requires two arguments.\n", parser.file.latin1(),
713 parser.line_no); 807 parser.line_no);
714 return FALSE; 808 return FALSE;
715 } 809 }
716 QRegExp regx(args[1]); 810 QRegExp regx(args[1]);
717 QStringList &l = place[args[0]]; 811 QStringList &l = place[args[0]];
718 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { 812 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
719 if(regx.exactMatch((*it))) 813 if(regx.exactMatch((*it)))
720 return TRUE; 814 return TRUE;
721 } 815 }
722 return FALSE; 816 return FALSE;
723 } else if(func == "infile") { 817 } else if(func == "infile") {
724 if(args.count() < 2 || args.count() > 3) { 818 if(args.count() < 2 || args.count() > 3) {
725 fprintf(stderr, "%s:%d: infile(file, var, val) requires at least 2 arguments.\n", 819 fprintf(stderr, "%s:%d: infile(file, var, val) requires at least 2 arguments.\n",
726 parser.file.latin1(), parser.line_no); 820 parser.file.latin1(), parser.line_no);
727 return FALSE; 821 return FALSE;
728 } 822 }
729 QMakeProject proj; 823 QMakeProject proj;
730 QString file = args[0]; 824 QString file = args[0];
731 doVariableReplace(file, place); 825 doVariableReplace(file, place);
732 fixEnvVariables(file); 826 fixEnvVariables(file);
733 int di = file.findRev(Option::dir_sep); 827 int di = file.findRev(Option::dir_sep);
734 QDir sunworkshop42workaround = QDir::current(); 828 QDir sunworkshop42workaround = QDir::current();
735 QString oldpwd = sunworkshop42workaround.currentDirPath(); 829 QString oldpwd = sunworkshop42workaround.currentDirPath();
736 if(di != -1) { 830 if(di != -1) {
737 if(!QDir::setCurrent(file.left(file.findRev(Option::dir_sep)))) { 831 if(!QDir::setCurrent(file.left(file.findRev(Option::dir_sep)))) {
738 fprintf(stderr, "Cannot find directory: %s\n", file.left(di).latin1()); 832 fprintf(stderr, "Cannot find directory: %s\n", file.left(di).latin1());
739 return FALSE; 833 return FALSE;
740 } 834 }
741 file = file.right(file.length() - di - 1); 835 file = file.right(file.length() - di - 1);
742 } 836 }
743 parser_info pi = parser; 837 parser_info pi = parser;
744 bool ret = !proj.read(file, oldpwd); 838 bool ret = !proj.read(file, oldpwd);
745 parser = pi; 839 parser = pi;
746 if(ret) { 840 if(ret) {
747 fprintf(stderr, "Error processing project file: %s\n", file.latin1()); 841 fprintf(stderr, "Error processing project file: %s\n", file.latin1());
748 QDir::setCurrent(oldpwd); 842 QDir::setCurrent(oldpwd);
749 return FALSE; 843 return FALSE;
750 } 844 }
751 if(args.count() == 2) { 845 if(args.count() == 2) {
752 ret = !proj.isEmpty(args[1]); 846 ret = !proj.isEmpty(args[1]);
753 } else { 847 } else {
754 QRegExp regx(args[2]); 848 QRegExp regx(args[2]);
755 QStringList &l = proj.values(args[1]); 849 QStringList &l = proj.values(args[1]);
756 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { 850 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
757 if(regx.exactMatch((*it))) { 851 if(regx.exactMatch((*it))) {
758 ret = TRUE; 852 ret = TRUE;
759 break; 853 break;
760 } 854 }
761 } 855 }
762 } 856 }
763 QDir::setCurrent(oldpwd); 857 QDir::setCurrent(oldpwd);
764 return ret; 858 return ret;
765 } else if(func == "count") { 859 } else if(func == "count") {
766 if(args.count() != 2) { 860 if(args.count() != 2) {
767 fprintf(stderr, "%s:%d: count(var, count) requires two arguments.\n", parser.file.latin1(), 861 fprintf(stderr, "%s:%d: count(var, count) requires two arguments.\n", parser.file.latin1(),
768 parser.line_no); 862 parser.line_no);
769 return FALSE; 863 return FALSE;
770 } 864 }
771 return vars[args[0]].count() == args[1].toUInt(); 865 return vars[args[0]].count() == args[1].toUInt();
772 } else if(func == "isEmpty") { 866 } else if(func == "isEmpty") {
773 if(args.count() != 1) { 867 if(args.count() != 1) {
774 fprintf(stderr, "%s:%d: isEmpty(var) requires one argument.\n", parser.file.latin1(), 868 fprintf(stderr, "%s:%d: isEmpty(var) requires one argument.\n", parser.file.latin1(),
775 parser.line_no); 869 parser.line_no);
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(),
785 parser.line_no, func_desc.latin1()); 882 parser.line_no, func_desc.latin1());
786 return FALSE; 883 return FALSE;
787 } 884 }
788 885
789 QString file = args.first(); 886 QString file = args.first();
790 file = Option::fixPathToLocalOS(file); 887 file = Option::fixPathToLocalOS(file);
791 file.replace("\"", ""); 888 file.replace("\"", "");
792 doVariableReplace(file, place); 889 doVariableReplace(file, place);
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(),
846 parser.line_no, func.latin1()); 1007 parser.line_no, func.latin1());
847 return FALSE; 1008 return FALSE;
848 } 1009 }
849 QString msg = args.first(); 1010 QString msg = args.first();
850 if((msg.startsWith("\"") || msg.startsWith("'")) && msg.endsWith(msg.left(1))) 1011 if((msg.startsWith("\"") || msg.startsWith("'")) && msg.endsWith(msg.left(1)))
851 msg = msg.mid(1, msg.length()-2); 1012 msg = msg.mid(1, msg.length()-2);
852 msg.replace(QString("${QMAKE_FILE}"), parser.file.latin1()); 1013 msg.replace(QString("${QMAKE_FILE}"), parser.file.latin1());
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 {
862 fprintf(stderr, "%s:%d: Unknown test function: %s\n", parser.file.latin1(), parser.line_no, 1023 fprintf(stderr, "%s:%d: Unknown test function: %s\n", parser.file.latin1(), parser.line_no,
863 func.latin1()); 1024 func.latin1());
864 } 1025 }
865 return FALSE; 1026 return FALSE;
866} 1027}
867 1028
868bool 1029bool
869QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringList> &place) 1030QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringList> &place)
870{ 1031{
871 bool ret = FALSE; 1032 bool ret = FALSE;
872 for(QStringList::ConstIterator it = deps.begin(); it != deps.end(); ++it) { 1033 for(QStringList::ConstIterator it = deps.begin(); it != deps.end(); ++it) {
873 QString chk = (*it); 1034 QString chk = (*it);
874 if(chk.isEmpty()) 1035 if(chk.isEmpty())
875 continue; 1036 continue;
876 bool invert_test = (chk.left(1) == "!"); 1037 bool invert_test = (chk.left(1) == "!");
877 if(invert_test) 1038 if(invert_test)
878 chk = chk.right(chk.length() - 1); 1039 chk = chk.right(chk.length() - 1);
879 1040
880 bool test; 1041 bool test;
881 int lparen = chk.find('('); 1042 int lparen = chk.find('(');
882 if(lparen != -1) { /* if there is an lparen in the chk, it IS a function */ 1043 if(lparen != -1) { /* if there is an lparen in the chk, it IS a function */
883 int rparen = chk.findRev(')'); 1044 int rparen = chk.findRev(')');
884 if(rparen == -1) { 1045 if(rparen == -1) {
885 QCString error; 1046 QCString error;
886 error.sprintf("Function (in REQUIRES) missing right paren: %s", chk.latin1()); 1047 error.sprintf("Function (in REQUIRES) missing right paren: %s", chk.latin1());
887 qmake_error_msg(error); 1048 qmake_error_msg(error);
888 } else { 1049 } else {
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;
898 } 1059 }
899 if(!test) { 1060 if(!test) {
900 debug_msg(1, "Project Parser: %s:%d Failed test: REQUIRES = %s", 1061 debug_msg(1, "Project Parser: %s:%d Failed test: REQUIRES = %s",
901 parser.file.latin1(), parser.line_no, chk.latin1()); 1062 parser.file.latin1(), parser.line_no, chk.latin1());
902 place["QMAKE_FAILED_REQUIREMENTS"].append(chk); 1063 place["QMAKE_FAILED_REQUIREMENTS"].append(chk);
903 ret = FALSE; 1064 ret = FALSE;
904 } 1065 }
905 } 1066 }
906 return ret; 1067 return ret;
907} 1068}
908 1069
909 1070
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;
955 } else if(str[var_incr] == ')') { 1130 } else if(str[var_incr] == ')') {
956 parens--; 1131 parens--;
957 if(!parens) { 1132 if(!parens) {
958 var_incr++; 1133 var_incr++;
959 break; 1134 break;
960 } 1135 }
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++;
974 } 1150 }
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"
1016 "arguments.\n", parser.file.latin1(), parser.line_no); 1267 "arguments.\n", parser.file.latin1(), parser.line_no);
1017 } else { 1268 } else {
1018 QString glue, before, after; 1269 QString glue, before, after;
1019 if(arg_list.count() >= 2) 1270 if(arg_list.count() >= 2)
1020 glue = arg_list[1].replace("\"", "" ); 1271 glue = arg_list[1].replace("\"", "" );
1021 if(arg_list.count() >= 3) 1272 if(arg_list.count() >= 3)
1022 before = arg_list[2].replace("\"", "" ); 1273 before = arg_list[2].replace("\"", "" );
1023 if(arg_list.count() == 4) 1274 if(arg_list.count() == 4)
1024 after = arg_list[3].replace("\"", "" ); 1275 after = arg_list[3].replace("\"", "" );
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);
1033 } else { 1302 } else {
1034 QRegExp regx(arg_list[1]); 1303 QRegExp regx(arg_list[1]);
1035 const QStringList &var = place[varMap(arg_list.first())]; 1304 const QStringList &var = place[varMap(arg_list.first())];
1036 for(QStringList::ConstIterator vit = var.begin(); 1305 for(QStringList::ConstIterator vit = var.begin();
1037 vit != var.end(); ++vit) { 1306 vit != var.end(); ++vit) {
1038 if(regx.search(*vit) != -1) { 1307 if(regx.search(*vit) != -1) {
1039 if(!replacement.isEmpty()) 1308 if(!replacement.isEmpty())
1040 replacement += " "; 1309 replacement += " ";
1041 replacement += (*vit); 1310 replacement += (*vit);
1042 } 1311 }
1043 } 1312 }
1044 } 1313 }
1045 } else if(val.lower() == "system") { 1314 } else if(val.lower() == "system") {
1046 if(arg_list.count() != 1) { 1315 if(arg_list.count() != 1) {
1047 fprintf(stderr, "%s:%d system(execut) requires one argument\n", 1316 fprintf(stderr, "%s:%d system(execut) requires one argument\n",
1048 parser.file.latin1(), parser.line_no); 1317 parser.file.latin1(), parser.line_no);
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')
1058 buff[i] = ' '; 1327 buff[i] = ' ';
1059 } 1328 }
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 }
1068 } 1382 }
1069 //actually do replacement now.. 1383 //actually do replacement now..
1070 int mlen = var_incr - var_begin; 1384 int mlen = var_incr - var_begin;
1071 debug_msg(2, "Project Parser [var replace]: '%s' :: %s -> %s", str.latin1(), 1385 debug_msg(2, "Project Parser [var replace]: '%s' :: %s -> %s", str.latin1(),
1072 str.mid(var_begin, mlen).latin1(), replacement.latin1()); 1386 str.mid(var_begin, mlen).latin1(), replacement.latin1());
1073 str.replace(var_begin, mlen, replacement); 1387 str.replace(var_begin, mlen, replacement);
1074 var_begin += replacement.length(); 1388 var_begin += replacement.length();
1075 } 1389 }
1076 return str; 1390 return str;
1077} 1391}