summaryrefslogtreecommitdiff
path: root/qmake/project.cpp
Unidiff
Diffstat (limited to 'qmake/project.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--qmake/project.cpp407
1 files changed, 245 insertions, 162 deletions
diff --git a/qmake/project.cpp b/qmake/project.cpp
index 44eb503..834823d 100644
--- a/qmake/project.cpp
+++ b/qmake/project.cpp
@@ -45,147 +45,158 @@
45#ifdef Q_OS_UNIX 45#ifdef Q_OS_UNIX
46# include <unistd.h> 46# include <unistd.h>
47#endif 47#endif
48#include <stdio.h> 48#include <stdio.h>
49#include <stdlib.h> 49#include <stdlib.h>
50 50
51#ifdef Q_OS_WIN32 51#ifdef Q_OS_WIN32
52#define QT_POPEN _popen 52#define QT_POPEN _popen
53#else 53#else
54#define QT_POPEN popen 54#define QT_POPEN popen
55#endif 55#endif
56 56
57struct parser_info { 57struct parser_info {
58 QString file; 58 QString file;
59 int line_no; 59 int line_no;
60} parser; 60} parser;
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
66static QString varMap(const QString &x) 66static QString varMap(const QString &x)
67{ 67{
68 QString ret(x); 68 QString ret(x);
69 ret.replace(QRegExp("^TMAKE"), "QMAKE"); 69 if(ret.startsWith("TMAKE")) //tmake no more!
70 ret = "QMAKE" + ret.mid(5);
70 if(ret == "INTERFACES") 71 if(ret == "INTERFACES")
71 ret = "FORMS"; 72 ret = "FORMS";
73 if(ret == "QMAKE_POST_BUILD")
74 ret = "QMAKE_POST_LINK";
75 if(ret == "TARGETDEPS")
76 ret = "POST_TARGETDEPS";
72 return ret; 77 return ret;
73} 78}
74 79
75static QStringList split_arg_list(const QString &params) 80static QStringList split_arg_list(const QString &params)
76{ 81{
77 QStringList args; 82 QStringList args;
78 int last = 0, parens = 0; 83 int last = 0, parens = 0;
79 QChar quote = 0; 84 QChar quote = 0;
80 for(int x = 0; x < (int)params.length(); x++) { 85 for(int x = 0; x < (int)params.length(); x++) {
81 if(params[x] == ')') { 86 if(params[x] == ')') {
82 parens--; 87 parens--;
83 } else if(params[x] == '(') { 88 } else if(params[x] == '(') {
84 parens++; 89 parens++;
85 } else if(params[x] == quote) { 90 } else if(params[x] == quote) {
86 quote = 0; 91 quote = 0;
87 } else if(params[x] == '\'' || params[x] == '"') { 92 } else if(params[x] == '\'' || params[x] == '"') {
88 quote = params[x]; 93 quote = params[x];
89 } else if(!parens && !quote && params[x] == ',') { 94 } else if(!parens && !quote && params[x] == ',') {
90 args << params.mid(last, x - last); 95 args << params.mid(last, x - last);
91 last = x+1; 96 last = x+1;
92 } 97 }
93 } 98 }
94 if(last != (int)params.length()) 99 if(last != (int)params.length())
95 args << params.mid(last); 100 args << params.mid(last);
96 return args; 101 return args;
97} 102}
98 103
99static QStringList split_value_list(const QString &vals, bool do_semicolon=FALSE) 104static QStringList split_value_list(const QString &vals, bool do_semicolon=FALSE)
100{ 105{
101 int last = 0; 106 int last = 0;
102 QStringList ret; 107 QStringList ret;
103 QValueStack<QChar> quote; 108 QValueStack<QChar> quote;
104 for(int x = 0; x < (int)vals.length(); x++) { 109 for(int x = 0; x < (int)vals.length(); x++) {
105 if(!quote.isEmpty() && vals[x] == quote.top()) { 110 if(!quote.isEmpty() && vals[x] == quote.top()) {
106 quote.pop(); 111 quote.pop();
107 } else if(vals[x] == '\'' || vals[x] == '"') { 112 } else if(vals[x] == '\'' || vals[x] == '"') {
108 quote.push(vals[x]); 113 quote.push(vals[x]);
109 } else if(quote.isEmpty() && 114 } else if(quote.isEmpty() &&
110 ((do_semicolon && vals[x] == ';') || vals[x] == ' ')) { 115 ((do_semicolon && vals[x] == ';') || vals[x] == ' ')) {
111 ret << vals.mid(last, x - last); 116 ret << vals.mid(last, x - last);
112 last = x+1; 117 last = x+1;
113 } 118 }
114 } 119 }
115 if(last != (int)vals.length()) 120 if(last != (int)vals.length())
116 ret << vals.mid(last); 121 ret << vals.mid(last);
117 return ret; 122 return ret;
118} 123}
119 124
120QMakeProject::QMakeProject() 125QMakeProject::QMakeProject()
121{ 126{
122} 127}
123 128
124bool 129bool
125QMakeProject::parse(QString t, QMap<QString, QStringList> &place) 130QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
126{ 131{
127 QString s = t.simplifyWhiteSpace(); 132 QString s = t.simplifyWhiteSpace();
128 s.replace(QRegExp("#.*$"), ""); /* bye comments */ 133 int hash_mark = s.find('#');
134 if(hash_mark != -1) //good bye comments
135 s = s.left(hash_mark);
129 if(s.isEmpty()) /* blank_line */ 136 if(s.isEmpty()) /* blank_line */
130 return TRUE; 137 return TRUE;
131 138
132 if(s.stripWhiteSpace().left(1) == "}") { 139 if(s.stripWhiteSpace().left(1) == "}") {
133 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(), 140 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(),
134 parser.line_no, scope_block); 141 parser.line_no, scope_block);
135 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek); 142 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek);
136 scope_block--; 143 scope_block--;
137 s = s.mid(1).stripWhiteSpace(); 144 s = s.mid(1).stripWhiteSpace();
138 if(s.isEmpty()) 145 if(s.isEmpty())
139 return TRUE; 146 return TRUE;
140 } 147 }
141 if(!(scope_flag & (0x01 << scope_block))) { 148 if(!(scope_flag & (0x01 << scope_block))) {
142 /* adjust scope for each block which appears on a single line */ 149 /* adjust scope for each block which appears on a single line */
143 for(int i = (s.contains('{')-s.contains('}')); i; i--) 150 for(int i = (s.contains('{')-s.contains('}')); i; i--)
144 scope_flag &= ~(0x01 << (++scope_block)); 151 scope_flag &= ~(0x01 << (++scope_block));
145 debug_msg(1, "Project Parser: %s:%d : Ignored due to block being false.", 152 debug_msg(1, "Project Parser: %s:%d : Ignored due to block being false.",
146 parser.file.latin1(), parser.line_no); 153 parser.file.latin1(), parser.line_no);
147 return TRUE; 154 return TRUE;
148 } 155 }
149 156
150 QString scope, var, op; 157 QString scope, var, op;
151 QStringList val; 158 QStringList val;
152#define SKIP_WS(d) while(*d && (*d == ' ' || *d == '\t')) d++ 159#define SKIP_WS(d) while(*d && (*d == ' ' || *d == '\t')) d++
153 const char *d = s.latin1(); 160 const char *d = s.latin1();
154 SKIP_WS(d); 161 SKIP_WS(d);
155 bool scope_failed = FALSE, else_line = FALSE, or_op=FALSE; 162 bool scope_failed = FALSE, else_line = FALSE, or_op=FALSE;
156 int parens = 0, scope_count=0; 163 int parens = 0, scope_count=0;
157 while(*d && *d != '=') { 164 while(*d) {
158 if((*d == '+' || *d == '-' || *d == '*' || *d == '~')) { 165 if(!parens) {
159 if(*(d+1) == '=') { 166 if(*d == '=')
160 break; 167 break;
161 } else if(*(d+1) == ' ') { 168 if(*d == '+' || *d == '-' || *d == '*' || *d == '~') {
162 const char *k = d + 1; 169 if(*(d+1) == '=') {
163 SKIP_WS(k); 170 break;
164 if(*k == '=') { 171 } else if(*(d+1) == ' ') {
165 QString msg; 172 const char *k = d + 1;
166 qmake_error_msg(*d + "must be followed immediatly by ="); 173 SKIP_WS(k);
167 return FALSE; 174 if(*k == '=') {
175 QString msg;
176 qmake_error_msg(*d + "must be followed immediately by =");
177 return FALSE;
178 }
168 } 179 }
169 } 180 }
170 } 181 }
171 182
172 if ( *d == '(' ) 183 if ( *d == '(' )
173 ++parens; 184 ++parens;
174 else if ( *d == ')' ) 185 else if ( *d == ')' )
175 --parens; 186 --parens;
176 187
177 if(!parens && (*d == ':' || *d == '{' || *d == ')' || *d == '|')) { 188 if(!parens && (*d == ':' || *d == '{' || *d == ')' || *d == '|')) {
178 scope_count++; 189 scope_count++;
179 scope = var.stripWhiteSpace(); 190 scope = var.stripWhiteSpace();
180 if ( *d == ')' ) 191 if ( *d == ')' )
181 scope += *d; /* need this */ 192 scope += *d; /* need this */
182 var = ""; 193 var = "";
183 194
184 bool test = scope_failed; 195 bool test = scope_failed;
185 if(scope.lower() == "else") { 196 if(scope.lower() == "else") {
186 if(scope_count != 1 || test_status == TestNone) { 197 if(scope_count != 1 || test_status == TestNone) {
187 qmake_error_msg("Unexpected " + scope + " ('" + s + "')"); 198 qmake_error_msg("Unexpected " + scope + " ('" + s + "')");
188 return FALSE; 199 return FALSE;
189 } 200 }
190 else_line = TRUE; 201 else_line = TRUE;
191 test = (test_status == TestSeek); 202 test = (test_status == TestSeek);
@@ -196,49 +207,49 @@ QMakeProject::parse(QString t, QMap<QString, QStringList> &place)
196 QString comp_scope = scope; 207 QString comp_scope = scope;
197 bool invert_test = (comp_scope.left(1) == "!"); 208 bool invert_test = (comp_scope.left(1) == "!");
198 if(invert_test) 209 if(invert_test)
199 comp_scope = comp_scope.right(comp_scope.length()-1); 210 comp_scope = comp_scope.right(comp_scope.length()-1);
200 int lparen = comp_scope.find('('); 211 int lparen = comp_scope.find('(');
201 if(or_op || !scope_failed) { 212 if(or_op || !scope_failed) {
202 if(lparen != -1) { /* if there is an lparen in the scope, it IS a function */ 213 if(lparen != -1) { /* if there is an lparen in the scope, it IS a function */
203 int rparen = comp_scope.findRev(')'); 214 int rparen = comp_scope.findRev(')');
204 if(rparen == -1) { 215 if(rparen == -1) {
205 QCString error; 216 QCString error;
206 error.sprintf("Function missing right paren: %s ('%s')", 217 error.sprintf("Function missing right paren: %s ('%s')",
207 comp_scope.latin1(), s.latin1()); 218 comp_scope.latin1(), s.latin1());
208 qmake_error_msg(error); 219 qmake_error_msg(error);
209 return FALSE; 220 return FALSE;
210 } 221 }
211 QString func = comp_scope.left(lparen); 222 QString func = comp_scope.left(lparen);
212 test = doProjectTest(func, comp_scope.mid(lparen+1, rparen - lparen - 1), place); 223 test = doProjectTest(func, comp_scope.mid(lparen+1, rparen - lparen - 1), place);
213 if ( *d == ')' && !*(d+1) ) { 224 if ( *d == ')' && !*(d+1) ) {
214 if(invert_test) 225 if(invert_test)
215 test = !test; 226 test = !test;
216 test_status = (test ? TestFound : TestSeek); 227 test_status = (test ? TestFound : TestSeek);
217 return TRUE; /* assume we are done */ 228 return TRUE; /* assume we are done */
218 } 229 }
219 } else { 230 } else {
220 test = isActiveConfig(comp_scope.stripWhiteSpace()); 231 test = isActiveConfig(comp_scope.stripWhiteSpace(), TRUE);
221 } 232 }
222 if(invert_test) 233 if(invert_test)
223 test = !test; 234 test = !test;
224 } 235 }
225 } 236 }
226 if(!test && !scope_failed) 237 if(!test && !scope_failed)
227 debug_msg(1, "Project Parser: %s:%d : Test (%s) failed.", parser.file.latin1(), 238 debug_msg(1, "Project Parser: %s:%d : Test (%s) failed.", parser.file.latin1(),
228 parser.line_no, scope.latin1()); 239 parser.line_no, scope.latin1());
229 if(test == or_op) 240 if(test == or_op)
230 scope_failed = !test; 241 scope_failed = !test;
231 or_op = (*d == '|'); 242 or_op = (*d == '|');
232 if(*d == '{') { /* scoping block */ 243 if(*d == '{') { /* scoping block */
233 if(!scope_failed) 244 if(!scope_failed)
234 scope_flag |= (0x01 << (++scope_block)); 245 scope_flag |= (0x01 << (++scope_block));
235 else 246 else
236 scope_flag &= ~(0x01 << (++scope_block)); 247 scope_flag &= ~(0x01 << (++scope_block));
237 debug_msg(1, "Project Parser: %s:%d : Entering block %d (%d).", parser.file.latin1(), 248 debug_msg(1, "Project Parser: %s:%d : Entering block %d (%d).", parser.file.latin1(),
238 parser.line_no, scope_block, !scope_failed); 249 parser.line_no, scope_block, !scope_failed);
239 } 250 }
240 } else { 251 } else {
241 var += *d; 252 var += *d;
242 } 253 }
243 d++; 254 d++;
244 } 255 }
@@ -266,49 +277,49 @@ QMakeProject::parse(QString t, QMap<QString, QStringList> &place)
266 parser.line_no, scope_block); 277 parser.line_no, scope_block);
267 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek); 278 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek);
268 scope_block--; 279 scope_block--;
269 vals.truncate(vals.length()-1); 280 vals.truncate(vals.length()-1);
270 } else if(rbraces != lbraces) { 281 } else if(rbraces != lbraces) {
271 warn_msg(WarnParser, "Possible braces mismatch {%s} %s:%d", 282 warn_msg(WarnParser, "Possible braces mismatch {%s} %s:%d",
272 vals.latin1(), parser.file.latin1(), parser.line_no); 283 vals.latin1(), parser.file.latin1(), parser.line_no);
273 } 284 }
274 doVariableReplace(vals, place); 285 doVariableReplace(vals, place);
275 286
276 var = var.stripWhiteSpace(); 287 var = var.stripWhiteSpace();
277#undef SKIP_WS 288#undef SKIP_WS
278 289
279 if(!var.isEmpty() && Option::mkfile::do_preprocess) { 290 if(!var.isEmpty() && Option::mkfile::do_preprocess) {
280 static QString last_file("*none*"); 291 static QString last_file("*none*");
281 if(parser.file != last_file) { 292 if(parser.file != last_file) {
282 fprintf(stderr, "#file %s:%d\n", parser.file.latin1(), parser.line_no); 293 fprintf(stderr, "#file %s:%d\n", parser.file.latin1(), parser.line_no);
283 last_file = parser.file; 294 last_file = parser.file;
284 } 295 }
285 fprintf(stderr, "%s %s %s\n", var.latin1(), op.latin1(), vals.latin1()); 296 fprintf(stderr, "%s %s %s\n", var.latin1(), op.latin1(), vals.latin1());
286 } 297 }
287 var = varMap(var); //backwards compatability 298 var = varMap(var); //backwards compatability
288 299
289 /* vallist is the broken up list of values */ 300 /* vallist is the broken up list of values */
290 QStringList vallist = split_value_list(vals, (var == "DEPENDPATH" || var == "INCLUDEPATH")); 301 QStringList vallist = split_value_list(vals, (var == "DEPENDPATH" || var == "INCLUDEPATH"));
291 if(!vallist.grep("=").isEmpty()) 302 if(!vallist.grep("=").isEmpty())
292 warn_msg(WarnParser, "Detected possible line continuation: {%s} %s:%d", 303 warn_msg(WarnParser, "Detected possible line continuation: {%s} %s:%d",
293 var.latin1(), parser.file.latin1(), parser.line_no); 304 var.latin1(), parser.file.latin1(), parser.line_no);
294 305
295 QStringList &varlist = place[var]; /* varlist is the list in the symbol table */ 306 QStringList &varlist = place[var]; /* varlist is the list in the symbol table */
296 debug_msg(1, "Project Parser: %s:%d :%s: :%s: (%s)", parser.file.latin1(), parser.line_no, 307 debug_msg(1, "Project Parser: %s:%d :%s: :%s: (%s)", parser.file.latin1(), parser.line_no,
297 var.latin1(), op.latin1(), vallist.join(" :: ").latin1()); 308 var.latin1(), op.latin1(), vallist.join(" :: ").latin1());
298 309
299 /* now do the operation */ 310 /* now do the operation */
300 if(op == "~=") { 311 if(op == "~=") {
301 if(vallist.count() != 1) { 312 if(vallist.count() != 1) {
302 qmake_error_msg("~= operator only accepts one right hand paramater ('" + 313 qmake_error_msg("~= operator only accepts one right hand paramater ('" +
303 s + "')"); 314 s + "')");
304 return FALSE; 315 return FALSE;
305 } 316 }
306 QString val(vallist.first()); 317 QString val(vallist.first());
307 if(val.length() < 4 || val.at(0) != 's') { 318 if(val.length() < 4 || val.at(0) != 's') {
308 qmake_error_msg("~= operator only can handle s/// function ('" + 319 qmake_error_msg("~= operator only can handle s/// function ('" +
309 s + "')"); 320 s + "')");
310 return FALSE; 321 return FALSE;
311 } 322 }
312 QChar sep = val.at(1); 323 QChar sep = val.at(1);
313 QStringList func = QStringList::split(sep, val, TRUE); 324 QStringList func = QStringList::split(sep, val, TRUE);
314 if(func.count() < 3 || func.count() > 4) { 325 if(func.count() < 3 || func.count() > 4) {
@@ -334,162 +345,163 @@ QMakeProject::parse(QString t, QMap<QString, QStringList> &place)
334 if(op == "=") { 345 if(op == "=") {
335 if(!varlist.isEmpty()) 346 if(!varlist.isEmpty())
336 warn_msg(WarnParser, "Operator=(%s) clears variables previously set: %s:%d", 347 warn_msg(WarnParser, "Operator=(%s) clears variables previously set: %s:%d",
337 var.latin1(), parser.file.latin1(), parser.line_no); 348 var.latin1(), parser.file.latin1(), parser.line_no);
338 varlist.clear(); 349 varlist.clear();
339 } 350 }
340 for(QStringList::Iterator valit = vallist.begin(); 351 for(QStringList::Iterator valit = vallist.begin();
341 valit != vallist.end(); ++valit) { 352 valit != vallist.end(); ++valit) {
342 if((*valit).isEmpty()) 353 if((*valit).isEmpty())
343 continue; 354 continue;
344 if((op == "*=" && !(*varlist.find((*valit)))) || 355 if((op == "*=" && !(*varlist.find((*valit)))) ||
345 op == "=" || op == "+=") 356 op == "=" || op == "+=")
346 varlist.append((*valit)); 357 varlist.append((*valit));
347 else if(op == "-=") 358 else if(op == "-=")
348 varlist.remove((*valit)); 359 varlist.remove((*valit));
349 } 360 }
350 } 361 }
351 if(var == "REQUIRES") /* special case to get communicated to backends! */ 362 if(var == "REQUIRES") /* special case to get communicated to backends! */
352 doProjectCheckReqs(vallist, place); 363 doProjectCheckReqs(vallist, place);
353 364
354 return TRUE; 365 return TRUE;
355} 366}
356 367
357bool 368bool
358QMakeProject::read(QString file, QMap<QString, QStringList> &place) 369QMakeProject::read(const QString &file, QMap<QString, QStringList> &place)
359{ 370{
360 parser_info pi = parser; 371 parser_info pi = parser;
361 /* scope blocks start at true */ 372 /* scope blocks start at true */
362 test_status = TestNone; 373 test_status = TestNone;
363 scope_flag = 0x01; 374 scope_flag = 0x01;
364 scope_block = 0; 375 scope_block = 0;
365 376
366 file = Option::fixPathToLocalOS(file); 377 QString filename = Option::fixPathToLocalOS(file);
367 doVariableReplace(file, place); 378 doVariableReplace(filename, place);
368 bool ret = FALSE, using_stdin = FALSE; 379 bool ret = FALSE, using_stdin = FALSE;
369 QFile qfile; 380 QFile qfile;
370 if(!strcmp(file, "-")) { 381 if(!strcmp(filename, "-")) {
371 qfile.setName(""); 382 qfile.setName("");
372 ret = qfile.open(IO_ReadOnly, stdin); 383 ret = qfile.open(IO_ReadOnly, stdin);
373 using_stdin = TRUE; 384 using_stdin = TRUE;
374 } else { 385 } else {
375 qfile.setName(file); 386 qfile.setName(filename);
376 ret = qfile.open(IO_ReadOnly); 387 ret = qfile.open(IO_ReadOnly);
377 } 388 }
378 if ( ret ) { 389 if ( ret ) {
379 QTextStream t( &qfile ); 390 QTextStream t( &qfile );
380 QString s, line; 391 QString s, line;
381 parser.file = file; 392 parser.file = filename;
382 parser.line_no = 0; 393 parser.line_no = 0;
383 while ( !t.eof() ) { 394 while ( !t.eof() ) {
384 parser.line_no++; 395 parser.line_no++;
385 line = t.readLine().stripWhiteSpace(); 396 line = t.readLine().stripWhiteSpace();
386 int prelen = line.length(); 397 int prelen = line.length();
387 line.replace(QRegExp("#.*$"), ""); // bye comments 398 {
399 int hash_mark = line.find('#');
400 if(hash_mark != -1) //bye comments
401 line = line.left(hash_mark);
402 }
388 if(!line.isEmpty() && line.right(1) == "\\") { 403 if(!line.isEmpty() && line.right(1) == "\\") {
389 line.truncate(line.length() - 1); 404 line.truncate(line.length() - 1);
390 s += line + " "; 405 s += line + " ";
391 } else if(!line.isEmpty() || (line.isEmpty() && !prelen)) { 406 } else if(!line.isEmpty() || (line.isEmpty() && !prelen)) {
392 if(s.isEmpty() && line.isEmpty()) 407 if(s.isEmpty() && line.isEmpty())
393 continue; 408 continue;
394 if(!line.isEmpty()) 409 if(!line.isEmpty())
395 s += line; 410 s += line;
396 if(!s.isEmpty()) { 411 if(!s.isEmpty()) {
397 if(!(ret = parse(s, place))) 412 if(!(ret = parse(s, place)))
398 break; 413 break;
399 s = ""; 414 s = "";
400 } 415 }
401 } 416 }
402 } 417 }
403 if(!using_stdin) 418 if(!using_stdin)
404 qfile.close(); 419 qfile.close();
405 } 420 }
406 parser = pi; 421 parser = pi;
407 return ret; 422 return ret;
408} 423}
409 424
410bool 425bool
411QMakeProject::read(QString project, QString) 426QMakeProject::read(const QString &project, const QString &, bool just_project)
412{ 427{
428 if(just_project) { //nothing more, nothing less
429 pfile = project;
430 if(pfile != "-" && !QFile::exists(pfile) && pfile.right(4) != ".pro")
431 pfile += ".pro";
432 return read(pfile, vars);
433 }
434
413 if(cfile.isEmpty()) { 435 if(cfile.isEmpty()) {
414 // hack to get the Option stuff in there 436 // hack to get the Option stuff in there
415 base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext; 437 base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext;
416 base_vars["QMAKE_EXT_H"] = Option::h_ext; 438 base_vars["QMAKE_EXT_H"] = Option::h_ext;
439 if(!Option::user_template_prefix.isEmpty())
440 base_vars["TEMPLATE_PREFIX"] = Option::user_template_prefix;
417 441
418 /* parse the cache */ 442 /* parse the cache */
419 if(Option::mkfile::do_cache) { 443 if(Option::mkfile::do_cache) {
420 if(Option::mkfile::cachefile.isEmpty()) { //find it as it has not been specified 444 if(Option::mkfile::cachefile.isEmpty()) { //find it as it has not been specified
421 QString dir = QDir::convertSeparators(Option::output_dir); 445 QString dir = QDir::convertSeparators(Option::output_dir);
422 while(!QFile::exists((Option::mkfile::cachefile = dir + 446 while(!QFile::exists((Option::mkfile::cachefile = dir +
423 QDir::separator() + ".qmake.cache"))) { 447 QDir::separator() + ".qmake.cache"))) {
424 dir = dir.left(dir.findRev(QDir::separator())); 448 dir = dir.left(dir.findRev(QDir::separator()));
425 if(dir.isEmpty() || dir.find(QDir::separator()) == -1) { 449 if(dir.isEmpty() || dir.find(QDir::separator()) == -1) {
426 Option::mkfile::cachefile = ""; 450 Option::mkfile::cachefile = "";
427 break; 451 break;
428 } 452 }
429 if(Option::mkfile::cachefile_depth == -1) 453 if(Option::mkfile::cachefile_depth == -1)
430 Option::mkfile::cachefile_depth = 1; 454 Option::mkfile::cachefile_depth = 1;
431 else 455 else
432 Option::mkfile::cachefile_depth++; 456 Option::mkfile::cachefile_depth++;
433 } 457 }
434 } 458 }
435 if(!Option::mkfile::cachefile.isEmpty()) { 459 if(!Option::mkfile::cachefile.isEmpty()) {
436 read(Option::mkfile::cachefile, cache); 460 read(Option::mkfile::cachefile, cache);
437 if(Option::mkfile::qmakespec.isEmpty() && !cache["QMAKESPEC"].isEmpty()) 461 if(Option::mkfile::qmakespec.isEmpty() && !cache["QMAKESPEC"].isEmpty())
438 Option::mkfile::qmakespec = cache["QMAKESPEC"].first(); 462 Option::mkfile::qmakespec = cache["QMAKESPEC"].first();
439 } 463 }
440 } 464 }
441 /* parse mkspec */ 465 /* parse mkspec */
442 QStringList mkspec_roots; 466 QStringList mkspec_roots;
443 /* prefer $QTDIR if it is set */ 467 /* prefer $QTDIR if it is set */
444 /* prefer QMAKESPECSDIR -cl */ 468 if (getenv("QTDIR"))
445
446 if (getenv("QTDIR")) {
447 mkspec_roots << getenv("QTDIR"); 469 mkspec_roots << getenv("QTDIR");
448 }
449 mkspec_roots << qInstallPathData(); 470 mkspec_roots << qInstallPathData();
450
451 if (Option::mkfile::qmakespec.isEmpty() && getenv("QMAKESPECSDIR")){
452 QString mkspec = QString(getenv("QMAKESPECSDIR")) + QDir::separator() +
453 QDir::separator() + "default";
454 if(QFile::exists(mkspec))
455 Option::mkfile::qmakespec = mkspec;
456 }
457
458 if(Option::mkfile::qmakespec.isEmpty()) { 471 if(Option::mkfile::qmakespec.isEmpty()) {
459 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) { 472 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
460 QString mkspec = (*it) + QDir::separator() + QString("mkspecs") + 473 QString mkspec = (*it) + QDir::separator() + QString("mkspecs") +
461 QDir::separator() + "default"; 474 QDir::separator() + "default";
462 if(QFile::exists(mkspec)) { 475 if(QFile::exists(mkspec)) {
463 Option::mkfile::qmakespec = mkspec; 476 Option::mkfile::qmakespec = mkspec;
464 break; 477 break;
465 } 478 }
466 } 479 }
467 } 480 if(Option::mkfile::qmakespec.isEmpty()) {
468 481 fprintf(stderr, "QMAKESPEC has not been set, so configuration cannot be deduced.\n");
469 if(Option::mkfile::qmakespec.isEmpty()) { 482 return FALSE;
470 fprintf(stderr, "QMAKESPEC has not been set, so configuration cannot be deduced.\n"); 483 }
471 return FALSE;
472 } 484 }
473 485
474 if(QDir::isRelativePath(Option::mkfile::qmakespec)) { 486 if(QDir::isRelativePath(Option::mkfile::qmakespec)) {
475 bool found_mkspec = FALSE; 487 bool found_mkspec = FALSE;
476 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) { 488 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
477 QString mkspec = (*it) + QDir::separator() + QString("mkspecs") + 489 QString mkspec = (*it) + QDir::separator() + QString("mkspecs") +
478 QDir::separator() + Option::mkfile::qmakespec; 490 QDir::separator() + Option::mkfile::qmakespec;
479 if(QFile::exists(mkspec)) { 491 if(QFile::exists(mkspec)) {
480 found_mkspec = TRUE; 492 found_mkspec = TRUE;
481 Option::mkfile::qmakespec = mkspec; 493 Option::mkfile::qmakespec = mkspec;
482 break; 494 break;
483 } 495 }
484 } 496 }
485 if(!found_mkspec) { 497 if(!found_mkspec) {
486 fprintf(stderr, "Could not find mkspecs for your QMAKESPEC after trying:\n\t%s\n", 498 fprintf(stderr, "Could not find mkspecs for your QMAKESPEC after trying:\n\t%s\n",
487 mkspec_roots.join("\n\t").latin1()); 499 mkspec_roots.join("\n\t").latin1());
488 return FALSE; 500 return FALSE;
489 } 501 }
490 } 502 }
491 503
492 /* parse qmake configuration */ 504 /* parse qmake configuration */
493 QString spec = Option::mkfile::qmakespec + QDir::separator() + "qmake.conf"; 505 QString spec = Option::mkfile::qmakespec + QDir::separator() + "qmake.conf";
494 debug_msg(1, "QMAKESPEC conf: reading %s", spec.latin1()); 506 debug_msg(1, "QMAKESPEC conf: reading %s", spec.latin1());
495 if(!read(spec, base_vars)) { 507 if(!read(spec, base_vars)) {
@@ -523,196 +535,209 @@ QMakeProject::read(QString project, QString)
523 if(pfile != "-" && !QFile::exists(pfile) && pfile.right(4) != ".pro") 535 if(pfile != "-" && !QFile::exists(pfile) && pfile.right(4) != ".pro")
524 pfile += ".pro"; 536 pfile += ".pro";
525 537
526 if(!read(pfile, vars)) 538 if(!read(pfile, vars))
527 return FALSE; 539 return FALSE;
528 540
529 parser.line_no = 1; //really arg count now.. duh 541 parser.line_no = 1; //really arg count now.. duh
530 parser.file = "(internal)"; 542 parser.file = "(internal)";
531 for(QStringList::Iterator it = Option::after_user_vars.begin(); 543 for(QStringList::Iterator it = Option::after_user_vars.begin();
532 it != Option::after_user_vars.end(); ++it) { 544 it != Option::after_user_vars.end(); ++it) {
533 if(!parse((*it), vars)) { 545 if(!parse((*it), vars)) {
534 fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1()); 546 fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1());
535 return FALSE; 547 return FALSE;
536 } 548 }
537 parser.line_no++; 549 parser.line_no++;
538 } 550 }
539 551
540 /* now let the user override the template from an option.. */ 552 /* now let the user override the template from an option.. */
541 if(!Option::user_template.isEmpty()) { 553 if(!Option::user_template.isEmpty()) {
542 debug_msg(1, "Overriding TEMPLATE (%s) with: %s", vars["TEMPLATE"].first().latin1(), Option::user_template.latin1()); 554 debug_msg(1, "Overriding TEMPLATE (%s) with: %s", vars["TEMPLATE"].first().latin1(), Option::user_template.latin1());
543 vars["TEMPLATE"].clear(); 555 vars["TEMPLATE"].clear();
544 vars["TEMPLATE"].append(Option::user_template); 556 vars["TEMPLATE"].append(Option::user_template);
545 } 557 }
546 558
547 if(vars["TEMPLATE"].isEmpty()) 559 QStringList &templ = vars["TEMPLATE"];
548 vars["TEMPLATE"].append(QString("app")); 560 if(templ.isEmpty())
549 else 561 templ.append(QString("app"));
550 vars["TEMPLATE"].first().replace(QRegExp("\\.t$"), ""); 562 else if(vars["TEMPLATE"].first().endsWith(".t"))
551 if(!Option::user_template_prefix.isEmpty()) 563 templ = QStringList(templ.first().left(templ.first().length() - 2));
552 vars["TEMPLATE"].first().prepend(Option::user_template_prefix); 564 if ( !Option::user_template_prefix.isEmpty() ) {
565 templ.first().prepend(Option::user_template_prefix);
566 }
553 567
554 if(vars["TARGET"].isEmpty()) { 568 if(vars["TARGET"].isEmpty()) {
555 // ### why not simply use: 569 // ### why not simply use:
556 // QFileInfo fi(pfile); 570 // QFileInfo fi(pfile);
557 // fi.baseName(); 571 // fi.baseName();
558 QString tmp = pfile; 572 QString tmp = pfile;
559 if(tmp.findRev('/') != -1) 573 if(tmp.findRev('/') != -1)
560 tmp = tmp.right( tmp.length() - tmp.findRev('/') - 1 ); 574 tmp = tmp.right( tmp.length() - tmp.findRev('/') - 1 );
561 if(tmp.findRev('.') != -1) 575 if(tmp.findRev('.') != -1)
562 tmp = tmp.left(tmp.findRev('.')); 576 tmp = tmp.left(tmp.findRev('.'));
563 vars["TARGET"].append(tmp); 577 vars["TARGET"].append(tmp);
564 } 578 }
565 579
566 QString test_version = getenv("QTESTVERSION"); 580 QString test_version = getenv("QTESTVERSION");
567 if (!test_version.isEmpty()) { 581 if (!test_version.isEmpty()) {
568 QString s = vars["TARGET"].first(); 582 QString s = vars["TARGET"].first();
569 if (s == "qt" || s == "qt-mt" || s == "qte" || s == "qte-mt") { 583 if (s == "qt" || s == "qt-mt" || s == "qte" || s == "qte-mt") {
570 QString &ver = vars["VERSION"].first(); 584 QString &ver = vars["VERSION"].first();
571 // fprintf(stderr,"Current QT version number: " + ver + "\n"); 585 // fprintf(stderr,"Current QT version number: " + ver + "\n");
572 if (ver != "" && ver != test_version) { 586 if (ver != "" && ver != test_version) {
573 ver = test_version; 587 ver = test_version;
574 fprintf(stderr,"Changed QT version number to " + test_version + "!\n"); 588 fprintf(stderr,"Changed QT version number to " + test_version + "!\n");
575 } 589 }
576 } 590 }
577 } 591 }
578 return TRUE; 592 return TRUE;
579} 593}
580 594
581bool 595bool
582QMakeProject::isActiveConfig(const QString &x) 596QMakeProject::isActiveConfig(const QString &x, bool regex)
583{ 597{
584 if(x.isEmpty()) 598 if(x.isEmpty())
585 return TRUE; 599 return TRUE;
586 600
587 QRegExp re(x, FALSE, TRUE); 601 if((Option::target_mode == Option::TARG_MACX_MODE || Option::target_mode == Option::TARG_QNX6_MODE ||
588 if((Option::target_mode == Option::TARG_MACX_MODE || Option::target_mode == Option::TARG_QNX6_MODE || Option::target_mode == Option::TARG_UNIX_MODE) && 602 Option::target_mode == Option::TARG_UNIX_MODE) && x == "unix")
589 x == "unix")
590 return TRUE; 603 return TRUE;
591 else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx") 604 else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx")
592 return TRUE; 605 return TRUE;
593 else if(Option::target_mode == Option::TARG_QNX6_MODE && x == "qnx6") 606 else if(Option::target_mode == Option::TARG_QNX6_MODE && x == "qnx6")
594 return TRUE; 607 return TRUE;
595 else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9") 608 else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9")
596 return TRUE; 609 return TRUE;
597 else if((Option::target_mode == Option::TARG_MAC9_MODE || Option::target_mode == Option::TARG_MACX_MODE) && 610 else if((Option::target_mode == Option::TARG_MAC9_MODE || Option::target_mode == Option::TARG_MACX_MODE) &&
598 x == "mac") 611 x == "mac")
599 return TRUE; 612 return TRUE;
600 else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32") 613 else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32")
601 return TRUE; 614 return TRUE;
602 615
603 616
617 QRegExp re(x, FALSE, TRUE);
604 QString spec = Option::mkfile::qmakespec.right(Option::mkfile::qmakespec.length() - 618 QString spec = Option::mkfile::qmakespec.right(Option::mkfile::qmakespec.length() -
605 (Option::mkfile::qmakespec.findRev(QDir::separator())+1)); 619 (Option::mkfile::qmakespec.findRev(QDir::separator())+1));
606 if(re.exactMatch(spec)) 620 if((regex && re.exactMatch(spec)) || (!regex && spec == x))
607 return TRUE; 621 return TRUE;
608#ifdef Q_OS_UNIX 622#ifdef Q_OS_UNIX
609 else if(spec == "default") { 623 else if(spec == "default") {
610 static char *buffer = NULL; 624 static char *buffer = NULL;
611 if(!buffer) 625 if(!buffer)
612 buffer = (char *)malloc(1024); 626 buffer = (char *)malloc(1024);
613 int l = readlink(Option::mkfile::qmakespec, buffer, 1024); 627 int l = readlink(Option::mkfile::qmakespec, buffer, 1024);
614 if(l != -1) { 628 if(l != -1) {
615 buffer[l] = '\0'; 629 buffer[l] = '\0';
616 QString r = buffer; 630 QString r = buffer;
617 if(r.findRev('/') != -1) 631 if(r.findRev('/') != -1)
618 r = r.mid(r.findRev('/') + 1); 632 r = r.mid(r.findRev('/') + 1);
619 if(re.exactMatch(r)) 633 if((regex && re.exactMatch(r)) || (!regex && r == x))
620 return TRUE; 634 return TRUE;
621 } 635 }
622 } 636 }
623#endif 637#endif
624 638
625 639
626 QStringList &configs = vars["CONFIG"]; 640 QStringList &configs = vars["CONFIG"];
627 for(QStringList::Iterator it = configs.begin(); it != configs.end(); ++it) { 641 for(QStringList::Iterator it = configs.begin(); it != configs.end(); ++it) {
642 if((regex && re.exactMatch((*it))) || (!regex && (*it) == x))
628 if(re.exactMatch((*it))) 643 if(re.exactMatch((*it)))
629 return TRUE; 644 return TRUE;
630 } 645 }
631 return FALSE; 646 return FALSE;
632} 647}
633 648
634bool 649bool
635QMakeProject::doProjectTest(QString func, const QString &params, QMap<QString, QStringList> &place) 650QMakeProject::doProjectTest(const QString& func, const QString &params, QMap<QString, QStringList> &place)
636{ 651{
637 QStringList args = split_arg_list(params); 652 QStringList args = split_arg_list(params);
638 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) { 653 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) {
639 QString tmp = (*arit).stripWhiteSpace(); 654 QString tmp = (*arit).stripWhiteSpace();
640 if((tmp[0] == '\'' || tmp[0] == '"') && tmp.right(1) == tmp.left(1)) 655 if((tmp[0] == '\'' || tmp[0] == '"') && tmp.right(1) == tmp.left(1))
641 tmp = tmp.mid(1, tmp.length() - 2); 656 tmp = tmp.mid(1, tmp.length() - 2);
642 } 657 }
643 return doProjectTest(func.stripWhiteSpace(), args, place); 658 return doProjectTest(func.stripWhiteSpace(), args, place);
644} 659}
645 660
646bool 661bool
647QMakeProject::doProjectTest(QString func, QStringList args, QMap<QString, QStringList> &place) 662QMakeProject::doProjectTest(const QString& func, QStringList args, QMap<QString, QStringList> &place)
648{ 663{
649 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) { 664 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) {
650 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space 665 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space
651 doVariableReplace((*arit), place); 666 doVariableReplace((*arit), place);
652 } 667 }
653 debug_msg(1, "Running project test: %s( %s )", func.latin1(), args.join("::").latin1()); 668 debug_msg(1, "Running project test: %s( %s )", func.latin1(), args.join("::").latin1());
654 669
655 if(func == "requires") { 670 if(func == "requires") {
656 return doProjectCheckReqs(args, place); 671 return doProjectCheckReqs(args, place);
672 } else if(func == "equals") {
673 if(args.count() != 2) {
674 fprintf(stderr, "%s:%d: equals(variable, value) requires two arguments.\n", parser.file.latin1(),
675 parser.line_no);
676 return FALSE;
677 }
678 QString value = args[1];
679 if((value.left(1) == "\"" || value.left(1) == "'") && value.right(1) == value.left(1))
680 value = value.mid(1, value.length()-2);
681 return vars[args[0]].join(" ") == value;
657 } else if(func == "exists") { 682 } else if(func == "exists") {
658 if(args.count() != 1) { 683 if(args.count() != 1) {
659 fprintf(stderr, "%s:%d: exists(file) requires one argument.\n", parser.file.latin1(), 684 fprintf(stderr, "%s:%d: exists(file) requires one argument.\n", parser.file.latin1(),
660 parser.line_no); 685 parser.line_no);
661 return FALSE; 686 return FALSE;
662 } 687 }
663 QString file = args.first(); 688 QString file = args.first();
664 file = Option::fixPathToLocalOS(file); 689 file = Option::fixPathToLocalOS(file);
665 doVariableReplace(file, place); 690 doVariableReplace(file, place);
666 691
667 if(QFile::exists(file)) 692 if(QFile::exists(file))
668 return TRUE; 693 return TRUE;
669 //regular expression I guess 694 //regular expression I guess
670 QString dirstr = QDir::currentDirPath(); 695 QString dirstr = QDir::currentDirPath();
671 int slsh = file.findRev(Option::dir_sep); 696 int slsh = file.findRev(Option::dir_sep);
672 if(slsh != -1) { 697 if(slsh != -1) {
673 dirstr = file.left(slsh+1); 698 dirstr = file.left(slsh+1);
674 file = file.right(file.length() - slsh - 1); 699 file = file.right(file.length() - slsh - 1);
675 } 700 }
676 QDir dir(dirstr, file); 701 QDir dir(dirstr, file);
677 return dir.count() != 0; 702 return dir.count() != 0;
678 } else if(func == "system") { 703 } else if(func == "system") {
679 if(args.count() != 1) { 704 if(args.count() != 1) {
680 fprintf(stderr, "%s:%d: system(exec) requires one argument.\n", parser.file.latin1(), 705 fprintf(stderr, "%s:%d: system(exec) requires one argument.\n", parser.file.latin1(),
681 parser.line_no); 706 parser.line_no);
682 return FALSE; 707 return FALSE;
683 } 708 }
684 return system(args.first().latin1()) == 0; 709 return system(args.first().latin1()) == 0;
685 } else if(func == "contains") { 710 } else if(func == "contains") {
686 if(args.count() != 2) { 711 if(args.count() != 2) {
687 fprintf(stderr, "%s:%d: contains(var, val) requires two arguments.\n", parser.file.latin1(), 712 fprintf(stderr, "%s:%d: contains(var, val) requires two arguments.\n", parser.file.latin1(),
688 parser.line_no); 713 parser.line_no);
689 return FALSE; 714 return FALSE;
690 } 715 }
691 QRegExp regx(args[1]); 716 QRegExp regx(args[1]);
692 QStringList &l = place[args[0]]; 717 QStringList &l = place[args[0]];
693 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { 718 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
694 if(regx.exactMatch((*it))) 719 if(regx.exactMatch((*it)))
695 return TRUE; 720 return TRUE;
696 } 721 }
697 return FALSE; 722 return FALSE;
698 } else if(func == "infile") { 723 } else if(func == "infile") {
699 if(args.count() < 2 || args.count() > 3) { 724 if(args.count() < 2 || args.count() > 3) {
700 fprintf(stderr, "%s:%d: infile(file, var, val) requires at least 2 arguments.\n", 725 fprintf(stderr, "%s:%d: infile(file, var, val) requires at least 2 arguments.\n",
701 parser.file.latin1(), parser.line_no); 726 parser.file.latin1(), parser.line_no);
702 return FALSE; 727 return FALSE;
703 } 728 }
704 QMakeProject proj; 729 QMakeProject proj;
705 QString file = args[0]; 730 QString file = args[0];
706 doVariableReplace(file, place); 731 doVariableReplace(file, place);
707 fixEnvVariables(file); 732 fixEnvVariables(file);
708 int di = file.findRev(Option::dir_sep); 733 int di = file.findRev(Option::dir_sep);
709 QDir sunworkshop42workaround = QDir::current(); 734 QDir sunworkshop42workaround = QDir::current();
710 QString oldpwd = sunworkshop42workaround.currentDirPath(); 735 QString oldpwd = sunworkshop42workaround.currentDirPath();
711 if(di != -1) { 736 if(di != -1) {
712 if(!QDir::setCurrent(file.left(file.findRev(Option::dir_sep)))) { 737 if(!QDir::setCurrent(file.left(file.findRev(Option::dir_sep)))) {
713 fprintf(stderr, "Cannot find directory: %s\n", file.left(di).latin1()); 738 fprintf(stderr, "Cannot find directory: %s\n", file.left(di).latin1());
714 return FALSE; 739 return FALSE;
715 } 740 }
716 file = file.right(file.length() - di - 1); 741 file = file.right(file.length() - di - 1);
717 } 742 }
718 parser_info pi = parser; 743 parser_info pi = parser;
@@ -784,211 +809,269 @@ QMakeProject::doProjectTest(QString func, QStringList args, QMap<QString, QStrin
784#endif 809#endif
785 for(QStringList::Iterator it = feature_roots.begin(); it != feature_roots.end(); ++it) { 810 for(QStringList::Iterator it = feature_roots.begin(); it != feature_roots.end(); ++it) {
786 QString prf = (*it) + QDir::separator() + QString("mkspecs") + 811 QString prf = (*it) + QDir::separator() + QString("mkspecs") +
787 QDir::separator() + QString("features") + QDir::separator() + file; 812 QDir::separator() + QString("features") + QDir::separator() + file;
788 if(QFile::exists(prf)) { 813 if(QFile::exists(prf)) {
789 found = TRUE; 814 found = TRUE;
790 file = prf; 815 file = prf;
791 break; 816 break;
792 } 817 }
793 } 818 }
794 if(!found) { 819 if(!found) {
795 printf("Project LOAD(): Feature %s cannot be found.\n", args.first().latin1()); 820 printf("Project LOAD(): Feature %s cannot be found.\n", args.first().latin1());
796 exit(3); 821 exit(3);
797 } 822 }
798 } 823 }
799 } 824 }
800 } 825 }
801 826
802 debug_msg(1, "Project Parser: %s'ing file %s.", func.latin1(), file.latin1()); 827 debug_msg(1, "Project Parser: %s'ing file %s.", func.latin1(), file.latin1());
803 parser_info pi = parser; 828 parser_info pi = parser;
804 int sb = scope_block; 829 int sb = scope_block;
805 int sf = scope_flag; 830 int sf = scope_flag;
806 TestStatus sc = test_status; 831 TestStatus sc = test_status;
807 bool r = read(file.latin1(), place); 832 bool r = read(file.latin1(), place);
808 if(r) 833 if(r)
809 vars["QMAKE_INTERNAL_INCLUDED_FILES"].append(file); 834 vars["QMAKE_INTERNAL_INCLUDED_FILES"].append(file);
835 else
836 warn_msg(WarnParser, "%s:%d: Failure to include file %s.",
837 pi.file.latin1(), pi.line_no, file.latin1());
810 parser = pi; 838 parser = pi;
811 test_status = sc; 839 test_status = sc;
812 scope_flag = sf; 840 scope_flag = sf;
813 scope_block = sb; 841 scope_block = sb;
814 return r; 842 return r;
815 } else if(func == "error" || func == "message") { 843 } else if(func == "error" || func == "message") {
816 if(args.count() != 1) { 844 if(args.count() != 1) {
817 fprintf(stderr, "%s:%d: %s(message) requires one argument.\n", parser.file.latin1(), 845 fprintf(stderr, "%s:%d: %s(message) requires one argument.\n", parser.file.latin1(),
818 parser.line_no, func.latin1()); 846 parser.line_no, func.latin1());
819 return FALSE; 847 return FALSE;
820 } 848 }
821 QString msg = args.first(); 849 QString msg = args.first();
850 if((msg.startsWith("\"") || msg.startsWith("'")) && msg.endsWith(msg.left(1)))
851 msg = msg.mid(1, msg.length()-2);
852 msg.replace(QString("${QMAKE_FILE}"), parser.file.latin1());
853 msg.replace(QString("${QMAKE_LINE_NUMBER}"), QString::number(parser.line_no));
854 msg.replace(QString("${QMAKE_DATE}"), QDateTime::currentDateTime().toString());
822 doVariableReplace(msg, place); 855 doVariableReplace(msg, place);
823 fixEnvVariables(msg); 856 fixEnvVariables(msg);
824 printf("Project %s: %s\n", func.upper().latin1(), msg.latin1()); 857 printf("Project %s: %s\n", func.upper().latin1(), msg.latin1());
825 if(func == "message") 858 if(func == "message")
826 return TRUE; 859 return TRUE;
827 exit(2); 860 exit(2);
828 } else { 861 } else {
829 fprintf(stderr, "%s:%d: Unknown test function: %s\n", parser.file.latin1(), parser.line_no, 862 fprintf(stderr, "%s:%d: Unknown test function: %s\n", parser.file.latin1(), parser.line_no,
830 func.latin1()); 863 func.latin1());
831 } 864 }
832 return FALSE; 865 return FALSE;
833} 866}
834 867
835bool 868bool
836QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringList> &place) 869QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringList> &place)
837{ 870{
838 bool ret = FALSE; 871 bool ret = FALSE;
839 for(QStringList::ConstIterator it = deps.begin(); it != deps.end(); ++it) { 872 for(QStringList::ConstIterator it = deps.begin(); it != deps.end(); ++it) {
840 QString chk = (*it); 873 QString chk = (*it);
841 if(chk.isEmpty()) 874 if(chk.isEmpty())
842 continue; 875 continue;
843 bool invert_test = (chk.left(1) == "!"); 876 bool invert_test = (chk.left(1) == "!");
844 if(invert_test) 877 if(invert_test)
845 chk = chk.right(chk.length() - 1); 878 chk = chk.right(chk.length() - 1);
846 879
847 bool test; 880 bool test;
848 int lparen = chk.find('('); 881 int lparen = chk.find('(');
849 if(lparen != -1) { /* if there is an lparen in the chk, it IS a function */ 882 if(lparen != -1) { /* if there is an lparen in the chk, it IS a function */
850 int rparen = chk.findRev(')'); 883 int rparen = chk.findRev(')');
851 if(rparen == -1) { 884 if(rparen == -1) {
852 QCString error; 885 QCString error;
853 error.sprintf("Function (in REQUIRES) missing right paren: %s", chk.latin1()); 886 error.sprintf("Function (in REQUIRES) missing right paren: %s", chk.latin1());
854 qmake_error_msg(error); 887 qmake_error_msg(error);
855 } else { 888 } else {
856 QString func = chk.left(lparen); 889 QString func = chk.left(lparen);
857 test = doProjectTest(func, chk.mid(lparen+1, rparen - lparen - 1), place); 890 test = doProjectTest(func, chk.mid(lparen+1, rparen - lparen - 1), place);
858 } 891 }
859 } else { 892 } else {
860 test = isActiveConfig(chk); 893 test = isActiveConfig(chk, TRUE);
861 } 894 }
862 if(invert_test) { 895 if(invert_test) {
863 chk.prepend("!"); 896 chk.prepend("!");
864 test = !test; 897 test = !test;
865 } 898 }
866 if(!test) { 899 if(!test) {
867 debug_msg(1, "Project Parser: %s:%d Failed test: REQUIRES = %s", 900 debug_msg(1, "Project Parser: %s:%d Failed test: REQUIRES = %s",
868 parser.file.latin1(), parser.line_no, chk.latin1()); 901 parser.file.latin1(), parser.line_no, chk.latin1());
869 place["QMAKE_FAILED_REQUIREMENTS"].append(chk); 902 place["QMAKE_FAILED_REQUIREMENTS"].append(chk);
870 ret = FALSE; 903 ret = FALSE;
871 } 904 }
872 } 905 }
873 return ret; 906 return ret;
874} 907}
875 908
876 909
877QString 910QString
878QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &place) 911QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &place)
879{ 912{
880 for(int x = 0, rep; x < 5; x++) { 913 for(int var_begin, var_last=0; (var_begin = str.find("$$", var_last)) != -1; var_last = var_begin) {
881 QRegExp reg_var; 914 if(var_begin >= int( str.length() + 2 ) ) {
882 reg_var.setMinimal(TRUE); 915 break;
883 if( x == 0 ) //function blocked out by {}'s 916 } else if(var_begin != 0 && str[var_begin-1] == '\\') {
884 reg_var = QRegExp("\\$\\$\\{([a-zA-Z0-9_]*)\\((\\(.|(.*)\\)*)\\)\\}"); 917 str.replace(var_begin-1, 1, "");
885 else if( x == 1 ) //variables blocked out by {}'s 918 var_begin += 1;
886 reg_var = QRegExp("\\$\\$\\{([a-zA-Z0-9_\\.-]*)\\}"); 919 continue;
887 else if(x == 2) //environment 920 }
888 reg_var = QRegExp("\\$\\$\\(([a-zA-Z0-9_\\.-]*)\\)"); 921
889 else if(x == 3) //function 922 int var_incr = var_begin + 2;
890 reg_var = QRegExp("\\$\\$([a-zA-Z0-9_]*)\\((\\(.|(.*)\\)*)\\)"); 923 bool in_braces = FALSE, as_env = FALSE;
891 else if(x == 4) //normal variable 924 if(str[var_incr] == '{') {
892 reg_var = QRegExp("\\$\\$([a-zA-Z0-9_\\.-]*)"); 925 in_braces = TRUE;
893 while((rep = reg_var.search(str)) != -1) { 926 var_incr++;
894 QString replacement; 927 while(var_incr < int( str.length() ) &&
895 if(x == 2) {//environment 928 (str[var_incr] == ' ' || str[var_incr] == '\t' || str[var_incr] == '\n'))
896 replacement = getenv(reg_var.cap(1)); 929 var_incr++;
897 } else if(x == 0 || x == 3) { //function 930 }
898 QStringList args = split_arg_list(reg_var.cap(2)); 931 if(str[var_incr] == '(') {
899 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) { 932 as_env = TRUE;
900 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space 933 var_incr++;
901 doVariableReplace((*arit), place); 934 }
902 } 935 QString val, args;
903 debug_msg(1, "Running function: %s( %s )", reg_var.cap(1).latin1(), args.join("::").latin1()); 936 while(var_incr < int( str.length() ) &&
904 if(reg_var.cap(1).lower() == "member") { 937 (str[var_incr].isLetter() || str[var_incr].isNumber() || str[var_incr] == '.' || str[var_incr] == '_'))
905 if(args.count() < 1 || args.count() > 2) { 938 val += str[var_incr++];
906 fprintf(stderr, "%s:%d: member(var, place) requires two arguments.\n", 939 if(as_env) {
907 parser.file.latin1(), parser.line_no); 940 if(str[var_incr] != ')') {
908 } else { 941 var_incr++;
909 uint pos = 0; 942 warn_msg(WarnParser, "%s:%d: Unterminated env-variable replacement '%s' (%s)",
910 if(args.count() == 2) 943 parser.file.latin1(), parser.line_no,
911 pos = args[1].toInt(); 944 str.mid(var_begin, QMAX(var_incr - var_begin, int(str.length()))).latin1(), str.latin1());
912 const QStringList &var = place[varMap(args.first())]; 945 var_begin += var_incr;
913 if(var.count() >= pos) 946 continue;
914 replacement = var[pos]; 947 }
915 } 948 var_incr++;
916 } else if(reg_var.cap(1).lower() == "list") { 949 } else if(str[var_incr] == '(') { //args
917 if(args.count() != 1) { 950 for(int parens = 0; var_incr < int( str.length() ); var_incr++) {
918 fprintf(stderr, "%s:%d: list(vals) requires one" 951 if(str[var_incr] == '(') {
919 "argument.\n", parser.file.latin1(), parser.line_no); 952 parens++;
920 } else { 953 if(parens == 1)
921 static int x = 0; 954 continue;
922 replacement.sprintf(".QMAKE_INTERNAL_TMP_VAR_%d", x++); 955 } else if(str[var_incr] == ')') {
923 (*((QMap<QString, QStringList>*)&place))[replacement] = split_value_list(args.first()); 956 parens--;
924 } 957 if(!parens) {
925 } else if(reg_var.cap(1).lower() == "join") { 958 var_incr++;
926 if(args.count() < 1 || args.count() > 4) { 959 break;
927 fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four"
928 "arguments.\n", parser.file.latin1(), parser.line_no);
929 } else {
930 QString glue, before, after;
931 if(args.count() >= 2)
932 glue = args[1].replace("\"", "" );
933 if(args.count() >= 3)
934 before = args[2].replace("\"", "" );
935 if(args.count() == 4)
936 after = args[3].replace("\"", "" );
937 const QStringList &var = place[varMap(args.first())];
938 if(!var.isEmpty())
939 replacement = before + var.join(glue) + after;
940 } 960 }
941 } else if(reg_var.cap(1).lower() == "find") { 961 }
942 if(args.count() != 2) { 962 args += str[var_incr];
943 fprintf(stderr, "%s:%d find(var, str) requires two arguments\n", 963 }
944 parser.file.latin1(), parser.line_no); 964 }
945 } else { 965 if(var_incr > int( str.length() ) || (in_braces && str[var_incr] != '}')) {
946 QRegExp regx(args[1]); 966 var_incr++;
947 const QStringList &var = place[varMap(args.first())]; 967 warn_msg(WarnParser, "%s:%d: Unterminated variable replacement '%s' (%s)",
948 for(QStringList::ConstIterator vit = var.begin(); 968 parser.file.latin1(), parser.line_no,
949 vit != var.end(); ++vit) { 969 str.mid(var_begin, QMAX(var_incr - var_begin, int( str.length() ))).latin1(), str.latin1());
950 if(regx.search(*vit) != -1) { 970 var_begin += var_incr;
951 if(!replacement.isEmpty()) 971 continue;
952 replacement += " "; 972 } else if(in_braces) {
953 replacement += (*vit); 973 var_incr++;
954 } 974 }
975
976 QString replacement;
977 if(as_env) {
978 replacement = getenv(val);
979 } else if(args.isEmpty()) {
980 if(val.left(1) == ".")
981 replacement = "";
982 else if(val == "LITERAL_WHITESPACE")
983 replacement = "\t";
984 else
985 replacement = place[varMap(val)].join(" ");
986 } else {
987 QStringList arg_list = split_arg_list(args);
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());
993 if(val.lower() == "member") {
994 if(arg_list.count() < 1 || arg_list.count() > 2) {
995 fprintf(stderr, "%s:%d: member(var, place) requires two arguments.\n",
996 parser.file.latin1(), parser.line_no);
997 } 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())];
1002 if(var.count() >= pos)
1003 replacement = var[pos];
1004 }
1005 } else if(val.lower() == "list") {
1006 static int x = 0;
1007 replacement.sprintf(".QMAKE_INTERNAL_TMP_VAR_%d", x++);
1008 QStringList &lst = (*((QMap<QString, QStringList>*)&place))[replacement];
1009 lst.clear();
1010 for(QStringList::ConstIterator arg_it = arg_list.begin();
1011 arg_it != arg_list.end(); ++arg_it)
1012 lst += split_value_list((*arg_it));
1013 } else if(val.lower() == "join") {
1014 if(arg_list.count() < 1 || arg_list.count() > 4) {
1015 fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four"
1016 "arguments.\n", parser.file.latin1(), parser.line_no);
1017 } else {
1018 QString glue, before, after;
1019 if(arg_list.count() >= 2)
1020 glue = arg_list[1].replace("\"", "" );
1021 if(arg_list.count() >= 3)
1022 before = arg_list[2].replace("\"", "" );
1023 if(arg_list.count() == 4)
1024 after = arg_list[3].replace("\"", "" );
1025 const QStringList &var = place[varMap(arg_list.first())];
1026 if(!var.isEmpty())
1027 replacement = before + var.join(glue) + after;
1028 }
1029 } else if(val.lower() == "find") {
1030 if(arg_list.count() != 2) {
1031 fprintf(stderr, "%s:%d find(var, str) requires two arguments\n",
1032 parser.file.latin1(), parser.line_no);
1033 } else {
1034 QRegExp regx(arg_list[1]);
1035 const QStringList &var = place[varMap(arg_list.first())];
1036 for(QStringList::ConstIterator vit = var.begin();
1037 vit != var.end(); ++vit) {
1038 if(regx.search(*vit) != -1) {
1039 if(!replacement.isEmpty())
1040 replacement += " ";
1041 replacement += (*vit);
955 } 1042 }
956 } 1043 }
957 } else if(reg_var.cap(1).lower() == "system") { 1044 }
958 if(args.count() != 1) { 1045 } else if(val.lower() == "system") {
959 fprintf(stderr, "%s:%d system(execut) requires one argument\n", 1046 if(arg_list.count() != 1) {
960 parser.file.latin1(), parser.line_no); 1047 fprintf(stderr, "%s:%d system(execut) requires one argument\n",
961 } else { 1048 parser.file.latin1(), parser.line_no);
962 char buff[256]; 1049 } else {
963 FILE *proc = QT_POPEN(args.join(" ").latin1(), "r"); 1050 char buff[256];
964 while(proc && !feof(proc)) { 1051 FILE *proc = QT_POPEN(arg_list.join(" ").latin1(), "r");
965 int read_in = fread(buff, 1, 255, proc); 1052 while(proc && !feof(proc)) {
966 if(!read_in) 1053 int read_in = fread(buff, 1, 255, proc);
967 break; 1054 if(!read_in)
968 for(int i = 0; i < read_in; i++) { 1055 break;
969 if(buff[i] == '\n' || buff[i] == '\t') 1056 for(int i = 0; i < read_in; i++) {
970 buff[i] = ' '; 1057 if(buff[i] == '\n' || buff[i] == '\t')
971 } 1058 buff[i] = ' ';
972 buff[read_in] = '\0';
973 replacement += buff;
974 } 1059 }
1060 buff[read_in] = '\0';
1061 replacement += buff;
975 } 1062 }
976 } else {
977 fprintf(stderr, "%s:%d: Unknown replace function: %s\n",
978 parser.file.latin1(), parser.line_no, reg_var.cap(1).latin1());
979 } 1063 }
980 } else { //variable 1064 } else {
981 if(reg_var.cap(1).left(1) == ".") 1065 fprintf(stderr, "%s:%d: Unknown replace function: %s\n",
982 replacement = ""; 1066 parser.file.latin1(), parser.line_no, val.latin1());
983 else if(reg_var.cap(1) == "LITERAL_WHITESPACE")
984 replacement = "\t";
985 else
986 replacement = place[varMap(reg_var.cap(1))].join(" ");
987 } 1067 }
988 debug_msg(2, "Project parser: %d (%s) :: %s -> %s", x, str.latin1(),
989 reg_var.capturedTexts().join("::").latin1(), replacement.latin1());
990 str.replace(rep, reg_var.matchedLength(), replacement);
991 } 1068 }
1069 //actually do replacement now..
1070 int mlen = var_incr - var_begin;
1071 debug_msg(2, "Project Parser [var replace]: '%s' :: %s -> %s", str.latin1(),
1072 str.mid(var_begin, mlen).latin1(), replacement.latin1());
1073 str.replace(var_begin, mlen, replacement);
1074 var_begin += replacement.length();
992 } 1075 }
993 return str; 1076 return str;
994} 1077}