-rw-r--r-- | qmake/project.cpp | 407 |
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 | |||
@@ -5,990 +5,1073 @@ | |||
5 | ** | 5 | ** |
6 | ** Created : 970521 | 6 | ** Created : 970521 |
7 | ** | 7 | ** |
8 | ** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. | 8 | ** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. |
9 | ** | 9 | ** |
10 | ** This file is part of the network module of the Qt GUI Toolkit. | 10 | ** This file is part of the network module of the Qt GUI Toolkit. |
11 | ** | 11 | ** |
12 | ** This file may be distributed under the terms of the Q Public License | 12 | ** 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 | 13 | ** as defined by Trolltech AS of Norway and appearing in the file |
14 | ** LICENSE.QPL included in the packaging of this file. | 14 | ** LICENSE.QPL included in the packaging of this file. |
15 | ** | 15 | ** |
16 | ** This file may be distributed and/or modified under the terms of the | 16 | ** 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 | 17 | ** GNU General Public License version 2 as published by the Free Software |
18 | ** Foundation and appearing in the file LICENSE.GPL included in the | 18 | ** Foundation and appearing in the file LICENSE.GPL included in the |
19 | ** packaging of this file. | 19 | ** packaging of this file. |
20 | ** | 20 | ** |
21 | ** Licensees holding valid Qt Enterprise Edition licenses may use this | 21 | ** Licensees holding valid Qt Enterprise Edition licenses may use this |
22 | ** file in accordance with the Qt Commercial License Agreement provided | 22 | ** file in accordance with the Qt Commercial License Agreement provided |
23 | ** with the Software. | 23 | ** with the Software. |
24 | ** | 24 | ** |
25 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | 25 | ** 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. | 26 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
27 | ** | 27 | ** |
28 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for | 28 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for |
29 | ** information about Qt Commercial License Agreements. | 29 | ** information about Qt Commercial License Agreements. |
30 | ** See http://www.trolltech.com/qpl/ for QPL licensing information. | 30 | ** See http://www.trolltech.com/qpl/ for QPL licensing information. |
31 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | 31 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. |
32 | ** | 32 | ** |
33 | ** Contact info@trolltech.com if any conditions of this licensing are | 33 | ** Contact info@trolltech.com if any conditions of this licensing are |
34 | ** not clear to you. | 34 | ** not clear to you. |
35 | ** | 35 | ** |
36 | **********************************************************************/ | 36 | **********************************************************************/ |
37 | 37 | ||
38 | #include "project.h" | 38 | #include "project.h" |
39 | #include "option.h" | 39 | #include "option.h" |
40 | #include <qfile.h> | 40 | #include <qfile.h> |
41 | #include <qdir.h> | 41 | #include <qdir.h> |
42 | #include <qregexp.h> | 42 | #include <qregexp.h> |
43 | #include <qtextstream.h> | 43 | #include <qtextstream.h> |
44 | #include <qvaluestack.h> | 44 | #include <qvaluestack.h> |
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 | ||
57 | struct parser_info { | 57 | struct parser_info { |
58 | QString file; | 58 | QString file; |
59 | int line_no; | 59 | int line_no; |
60 | } parser; | 60 | } parser; |
61 | static void qmake_error_msg(const char *msg) | 61 | static 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 | ||
66 | static QString varMap(const QString &x) | 66 | static 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 | ||
75 | static QStringList split_arg_list(const QString ¶ms) | 80 | static QStringList split_arg_list(const QString ¶ms) |
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 | ||
99 | static QStringList split_value_list(const QString &vals, bool do_semicolon=FALSE) | 104 | static 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 | ||
120 | QMakeProject::QMakeProject() | 125 | QMakeProject::QMakeProject() |
121 | { | 126 | { |
122 | } | 127 | } |
123 | 128 | ||
124 | bool | 129 | bool |
125 | QMakeProject::parse(QString t, QMap<QString, QStringList> &place) | 130 | QMakeProject::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); |
192 | debug_msg(1, "Project Parser: %s:%d : Else%s %s.", parser.file.latin1(), parser.line_no, | 203 | debug_msg(1, "Project Parser: %s:%d : Else%s %s.", parser.file.latin1(), parser.line_no, |
193 | scope == "else" ? "" : QString(" (" + scope + ")").latin1(), | 204 | scope == "else" ? "" : QString(" (" + scope + ")").latin1(), |
194 | test ? "considered" : "excluded"); | 205 | test ? "considered" : "excluded"); |
195 | } else { | 206 | } else { |
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 | } |
245 | if(!scope_count || (scope_count == 1 && else_line)) | 256 | if(!scope_count || (scope_count == 1 && else_line)) |
246 | test_status = TestNone; | 257 | test_status = TestNone; |
247 | else if(!else_line || test_status != TestFound) | 258 | else if(!else_line || test_status != TestFound) |
248 | test_status = (scope_failed ? TestSeek : TestFound); | 259 | test_status = (scope_failed ? TestSeek : TestFound); |
249 | if(scope_failed) | 260 | if(scope_failed) |
250 | return TRUE; /* oh well */ | 261 | return TRUE; /* oh well */ |
251 | if(!*d) { | 262 | if(!*d) { |
252 | if(!var.isEmpty()) | 263 | if(!var.isEmpty()) |
253 | qmake_error_msg("Parse Error ('" + s + "')"); | 264 | qmake_error_msg("Parse Error ('" + s + "')"); |
254 | return var.isEmpty(); /* allow just a scope */ | 265 | return var.isEmpty(); /* allow just a scope */ |
255 | } | 266 | } |
256 | 267 | ||
257 | SKIP_WS(d); | 268 | SKIP_WS(d); |
258 | for( ; *d && op.find('=') == -1; op += *(d++)); | 269 | for( ; *d && op.find('=') == -1; op += *(d++)); |
259 | op.replace(QRegExp("\\s"), ""); | 270 | op.replace(QRegExp("\\s"), ""); |
260 | 271 | ||
261 | SKIP_WS(d); | 272 | SKIP_WS(d); |
262 | QString vals(d); /* vals now contains the space separated list of values */ | 273 | QString vals(d); /* vals now contains the space separated list of values */ |
263 | int rbraces = vals.contains('}'), lbraces = vals.contains('{'); | 274 | int rbraces = vals.contains('}'), lbraces = vals.contains('{'); |
264 | if(scope_block && rbraces - lbraces == 1) { | 275 | if(scope_block && rbraces - lbraces == 1) { |
265 | debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(), | 276 | debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(), |
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) { |
315 | qmake_error_msg("~= operator only can handle s/// function ('" + | 326 | qmake_error_msg("~= operator only can handle s/// function ('" + |
316 | s + "')"); | 327 | s + "')"); |
317 | return FALSE; | 328 | return FALSE; |
318 | } | 329 | } |
319 | bool global = FALSE, case_sense = TRUE; | 330 | bool global = FALSE, case_sense = TRUE; |
320 | if(func.count() == 4) { | 331 | if(func.count() == 4) { |
321 | global = func[3].find('g') != -1; | 332 | global = func[3].find('g') != -1; |
322 | case_sense = func[3].find('i') == -1; | 333 | case_sense = func[3].find('i') == -1; |
323 | } | 334 | } |
324 | QRegExp regexp(func[1], case_sense); | 335 | QRegExp regexp(func[1], case_sense); |
325 | for(QStringList::Iterator varit = varlist.begin(); | 336 | for(QStringList::Iterator varit = varlist.begin(); |
326 | varit != varlist.end(); ++varit) { | 337 | varit != varlist.end(); ++varit) { |
327 | if((*varit).contains(regexp)) { | 338 | if((*varit).contains(regexp)) { |
328 | (*varit) = (*varit).replace(regexp, func[2]); | 339 | (*varit) = (*varit).replace(regexp, func[2]); |
329 | if(!global) | 340 | if(!global) |
330 | break; | 341 | break; |
331 | } | 342 | } |
332 | } | 343 | } |
333 | } else { | 344 | } else { |
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 | ||
357 | bool | 368 | bool |
358 | QMakeProject::read(QString file, QMap<QString, QStringList> &place) | 369 | QMakeProject::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 | ||
410 | bool | 425 | bool |
411 | QMakeProject::read(QString project, QString) | 426 | QMakeProject::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)) { |
496 | fprintf(stderr, "Failure to read QMAKESPEC conf file %s.\n", spec.latin1()); | 508 | fprintf(stderr, "Failure to read QMAKESPEC conf file %s.\n", spec.latin1()); |
497 | return FALSE; | 509 | return FALSE; |
498 | } | 510 | } |
499 | if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) { | 511 | if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) { |
500 | debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.latin1()); | 512 | debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.latin1()); |
501 | read(Option::mkfile::cachefile, base_vars); | 513 | read(Option::mkfile::cachefile, base_vars); |
502 | } | 514 | } |
503 | 515 | ||
504 | /* commandline */ | 516 | /* commandline */ |
505 | cfile = project; | 517 | cfile = project; |
506 | parser.line_no = 1; //really arg count now.. duh | 518 | parser.line_no = 1; //really arg count now.. duh |
507 | parser.file = "(internal)"; | 519 | parser.file = "(internal)"; |
508 | for(QStringList::Iterator it = Option::before_user_vars.begin(); | 520 | for(QStringList::Iterator it = Option::before_user_vars.begin(); |
509 | it != Option::before_user_vars.end(); ++it) { | 521 | it != Option::before_user_vars.end(); ++it) { |
510 | if(!parse((*it), base_vars)) { | 522 | if(!parse((*it), base_vars)) { |
511 | fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1()); | 523 | fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1()); |
512 | return FALSE; | 524 | return FALSE; |
513 | } | 525 | } |
514 | parser.line_no++; | 526 | parser.line_no++; |
515 | } | 527 | } |
516 | } | 528 | } |
517 | 529 | ||
518 | /* parse project file */ | 530 | /* parse project file */ |
519 | debug_msg(1, "Project file: reading %s", project.latin1()); | 531 | debug_msg(1, "Project file: reading %s", project.latin1()); |
520 | vars = base_vars; /* start with the base */ | 532 | vars = base_vars; /* start with the base */ |
521 | 533 | ||
522 | pfile = project; | 534 | pfile = project; |
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 | ||
581 | bool | 595 | bool |
582 | QMakeProject::isActiveConfig(const QString &x) | 596 | QMakeProject::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 | ||
634 | bool | 649 | bool |
635 | QMakeProject::doProjectTest(QString func, const QString ¶ms, QMap<QString, QStringList> &place) | 650 | QMakeProject::doProjectTest(const QString& func, const QString ¶ms, 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 | ||
646 | bool | 661 | bool |
647 | QMakeProject::doProjectTest(QString func, QStringList args, QMap<QString, QStringList> &place) | 662 | QMakeProject::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; |
719 | bool ret = !proj.read(file, oldpwd); | 744 | bool ret = !proj.read(file, oldpwd); |
720 | parser = pi; | 745 | parser = pi; |
721 | if(ret) { | 746 | if(ret) { |
722 | fprintf(stderr, "Error processing project file: %s\n", file.latin1()); | 747 | fprintf(stderr, "Error processing project file: %s\n", file.latin1()); |
723 | QDir::setCurrent(oldpwd); | 748 | QDir::setCurrent(oldpwd); |
724 | return FALSE; | 749 | return FALSE; |
725 | } | 750 | } |
726 | if(args.count() == 2) { | 751 | if(args.count() == 2) { |
727 | ret = !proj.isEmpty(args[1]); | 752 | ret = !proj.isEmpty(args[1]); |
728 | } else { | 753 | } else { |
729 | QRegExp regx(args[2]); | 754 | QRegExp regx(args[2]); |
730 | QStringList &l = proj.values(args[1]); | 755 | QStringList &l = proj.values(args[1]); |
731 | for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { | 756 | for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { |
732 | if(regx.exactMatch((*it))) { | 757 | if(regx.exactMatch((*it))) { |
733 | ret = TRUE; | 758 | ret = TRUE; |
734 | break; | 759 | break; |
735 | } | 760 | } |
736 | } | 761 | } |
737 | } | 762 | } |
738 | QDir::setCurrent(oldpwd); | 763 | QDir::setCurrent(oldpwd); |
739 | return ret; | 764 | return ret; |
740 | } else if(func == "count") { | 765 | } else if(func == "count") { |
741 | if(args.count() != 2) { | 766 | if(args.count() != 2) { |
742 | fprintf(stderr, "%s:%d: count(var, count) requires two arguments.\n", parser.file.latin1(), | 767 | fprintf(stderr, "%s:%d: count(var, count) requires two arguments.\n", parser.file.latin1(), |
743 | parser.line_no); | 768 | parser.line_no); |
744 | return FALSE; | 769 | return FALSE; |
745 | } | 770 | } |
746 | return vars[args[0]].count() == args[1].toUInt(); | 771 | return vars[args[0]].count() == args[1].toUInt(); |
747 | } else if(func == "isEmpty") { | 772 | } else if(func == "isEmpty") { |
748 | if(args.count() != 1) { | 773 | if(args.count() != 1) { |
749 | fprintf(stderr, "%s:%d: isEmpty(var) requires one argument.\n", parser.file.latin1(), | 774 | fprintf(stderr, "%s:%d: isEmpty(var) requires one argument.\n", parser.file.latin1(), |
750 | parser.line_no); | 775 | parser.line_no); |
751 | return FALSE; | 776 | return FALSE; |
752 | } | 777 | } |
753 | return vars[args[0]].isEmpty(); | 778 | return vars[args[0]].isEmpty(); |
754 | } else if(func == "include" || func == "load") { | 779 | } else if(func == "include" || func == "load") { |
755 | if(args.count() != 1) { | 780 | if(args.count() != 1) { |
756 | QString func_desc = "include(file)"; | 781 | QString func_desc = "include(file)"; |
757 | if(func == "load") | 782 | if(func == "load") |
758 | func_desc = "load(feature)"; | 783 | func_desc = "load(feature)"; |
759 | fprintf(stderr, "%s:%d: %s requires one argument.\n", parser.file.latin1(), | 784 | fprintf(stderr, "%s:%d: %s requires one argument.\n", parser.file.latin1(), |
760 | parser.line_no, func_desc.latin1()); | 785 | parser.line_no, func_desc.latin1()); |
761 | return FALSE; | 786 | return FALSE; |
762 | } | 787 | } |
763 | 788 | ||
764 | QString file = args.first(); | 789 | QString file = args.first(); |
765 | file = Option::fixPathToLocalOS(file); | 790 | file = Option::fixPathToLocalOS(file); |
766 | file.replace("\"", ""); | 791 | file.replace("\"", ""); |
767 | doVariableReplace(file, place); | 792 | doVariableReplace(file, place); |
768 | if(func == "load") { | 793 | if(func == "load") { |
769 | if(!file.endsWith(Option::prf_ext)) | 794 | if(!file.endsWith(Option::prf_ext)) |
770 | file += Option::prf_ext; | 795 | file += Option::prf_ext; |
771 | if(file.find(Option::dir_sep) == -1 || !QFile::exists(file)) { | 796 | if(file.find(Option::dir_sep) == -1 || !QFile::exists(file)) { |
772 | if(QFile::exists(Option::mkfile::qmakespec + QDir::separator() + file)) { | 797 | if(QFile::exists(Option::mkfile::qmakespec + QDir::separator() + file)) { |
773 | file.prepend(Option::mkfile::qmakespec + QDir::separator()); | 798 | file.prepend(Option::mkfile::qmakespec + QDir::separator()); |
774 | } else { | 799 | } else { |
775 | bool found = FALSE; | 800 | bool found = FALSE; |
776 | QStringList feature_roots; | 801 | QStringList feature_roots; |
777 | if(getenv("QTDIR")) | 802 | if(getenv("QTDIR")) |
778 | feature_roots << getenv("QTDIR"); | 803 | feature_roots << getenv("QTDIR"); |
779 | #ifdef QT_INSTALL_PREFIX | 804 | #ifdef QT_INSTALL_PREFIX |
780 | feature_roots << QT_INSTALL_PREFIX; | 805 | feature_roots << QT_INSTALL_PREFIX; |
781 | #endif | 806 | #endif |
782 | #ifdef QT_INSTALL_DATA | 807 | #ifdef QT_INSTALL_DATA |
783 | feature_roots << QT_INSTALL_DATA; | 808 | feature_roots << QT_INSTALL_DATA; |
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 | ||
835 | bool | 868 | bool |
836 | QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringList> &place) | 869 | QMakeProject::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 | ||
877 | QString | 910 | QString |
878 | QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &place) | 911 | QMakeProject::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 | } |