00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "project.h"
00037 #include "property.h"
00038 #include "option.h"
00039 #include <qfile.h>
00040 #include <qdir.h>
00041 #include <qregexp.h>
00042 #include <qtextstream.h>
00043 #include <qvaluestack.h>
00044 #ifdef Q_OS_UNIX
00045 # include <unistd.h>
00046 #endif
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049
00050 #ifdef Q_OS_WIN32
00051 #define QT_POPEN _popen
00052 #else
00053 #define QT_POPEN popen
00054 #endif
00055
00056 struct parser_info {
00057 QString file;
00058 int line_no;
00059 } parser;
00060
00061 static void qmake_error_msg(const char *msg)
00062 {
00063 fprintf(stderr, "%s:%d: %s\n", parser.file.latin1(), parser.line_no, msg);
00064 }
00065
00066 QStringList qmake_mkspec_paths()
00067 {
00068 QStringList ret;
00069 const QString concat = QDir::separator() + QString("mkspecs");
00070 if(const char *qmakepath = getenv("QMAKEPATH")) {
00071 #ifdef Q_OS_WIN
00072 QStringList lst = QStringList::split(';', qmakepath);
00073 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it) {
00074 QStringList lst2 = QStringList::split(':', (*it));
00075 for(QStringList::Iterator it2 = lst2.begin(); it2 != lst2.end(); ++it2)
00076 ret << ((*it2) + concat);
00077 }
00078 #else
00079 QStringList lst = QStringList::split(':', qmakepath);
00080 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it)
00081 ret << ((*it) + concat);
00082 #endif
00083 }
00084 if(const char *qtdir = getenv("QTDIR"))
00085 ret << (QString(qtdir) + concat);
00086 #ifdef QT_INSTALL_PREFIX
00087 ret << (QT_INSTALL_PREFIX + concat);
00088 #endif
00089 #if defined(HAVE_QCONFIG_CPP)
00090 ret << (qInstallPath() + concat);
00091 #endif
00092 #ifdef QT_INSTALL_DATA
00093 ret << (QT_INSTALL_DATA + concat);
00094 #endif
00095 #if defined(HAVE_QCONFIG_CPP)
00096 ret << (qInstallPathData() + concat);
00097 #endif
00098
00099
00100 if (getenv("QTDIR"))
00101 ret << getenv("QTDIR");
00102 ret << qInstallPathData();
00103 return ret;
00104 }
00105
00106 static QString varMap(const QString &x)
00107 {
00108 QString ret(x);
00109 if(ret.startsWith("TMAKE"))
00110 ret = "QMAKE" + ret.mid(5);
00111 else if(ret == "INTERFACES")
00112 ret = "FORMS";
00113 else if(ret == "QMAKE_POST_BUILD")
00114 ret = "QMAKE_POST_LINK";
00115 else if(ret == "TARGETDEPS")
00116 ret = "POST_TARGETDEPS";
00117 else if(ret == "LIBPATH")
00118 ret = "QMAKE_LIBDIR";
00119 else if(ret == "QMAKE_EXT_MOC")
00120 ret = "QMAKE_EXT_CPP_MOC";
00121 else if(ret == "QMAKE_MOD_MOC")
00122 ret = "QMAKE_H_MOD_MOC";
00123 else if(ret == "QMAKE_LFLAGS_SHAPP")
00124 ret = "QMAKE_LFLAGS_APP";
00125 else if(ret == "PRECOMPH")
00126 ret = "PRECOMPILED_HEADER";
00127 else if(ret == "PRECOMPCPP")
00128 ret = "PRECOMPILED_SOURCE";
00129 else if(ret == "INCPATH")
00130 ret = "INCLUDEPATH";
00131 return ret;
00132 }
00133
00134 static QStringList split_arg_list(const QString ¶ms)
00135 {
00136 QChar quote = 0;
00137 QStringList args;
00138 for(int x = 0, last = 0, parens = 0; x <= (int)params.length(); x++) {
00139 if(x == (int)params.length()) {
00140 QString mid = params.mid(last, x - last).stripWhiteSpace();
00141 if(mid[(int)mid.length()-1] == quote)
00142 mid.truncate(1);
00143 args << mid;
00144 } else if(params[x] == ')') {
00145 parens--;
00146 } else if(params[x] == '(') {
00147 parens++;
00148 } else if(params[x] == quote) {
00149 quote = 0;
00150 } else if(params[x] == '\'' || params[x] == '"') {
00151 quote = params[x];
00152 } else if(!parens && !quote && params[x] == ',') {
00153 args << params.mid(last, x - last).stripWhiteSpace();
00154 last = x+1;
00155 }
00156 }
00157 return args;
00158 }
00159
00160 static QStringList split_value_list(const QString &vals, bool do_semicolon=FALSE)
00161 {
00162 QString build;
00163 QStringList ret;
00164 QValueStack<QChar> quote;
00165 for(int x = 0; x < (int)vals.length(); x++) {
00166 if(x != (int)vals.length()-1 && vals[x] == '\\' && (vals[x+1] == '\'' || vals[x+1] == '"'))
00167 build += vals[x++];
00168 else if(!quote.isEmpty() && vals[x] == quote.top())
00169 quote.pop();
00170 else if(vals[x] == '\'' || vals[x] == '"')
00171 quote.push(vals[x]);
00172
00173 if(quote.isEmpty() && ((do_semicolon && vals[x] == ';') || vals[x] == ' ')) {
00174 ret << build;
00175 build = "";
00176 } else {
00177 build += vals[x];
00178 }
00179 }
00180 if(!build.isEmpty())
00181 ret << build;
00182 return ret;
00183 }
00184
00185 QMakeProject::QMakeProject()
00186 {
00187 prop = NULL;
00188 }
00189
00190 QMakeProject::QMakeProject(QMakeProperty *p)
00191 {
00192 prop = p;
00193 }
00194
00195 void
00196 QMakeProject::reset()
00197 {
00198
00199 test_status = TestNone;
00200 scope_flag = 0x01;
00201 scope_block = 0;
00202 }
00203
00204 bool
00205 QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
00206 {
00207 QString s = t.simplifyWhiteSpace();
00208 int hash_mark = s.find("#");
00209 if(hash_mark != -1)
00210 s = s.left(hash_mark);
00211 if(s.isEmpty())
00212 return TRUE;
00213
00214 if(s.stripWhiteSpace().left(1) == "}") {
00215 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(),
00216 parser.line_no, scope_block);
00217 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek);
00218 scope_block--;
00219 s = s.mid(1).stripWhiteSpace();
00220 if(s.isEmpty())
00221 return TRUE;
00222 }
00223 if(!(scope_flag & (0x01 << scope_block))) {
00224
00225 for(int i = (s.contains('{')-s.contains('}')); i>0; i--)
00226 scope_flag &= ~(0x01 << (++scope_block));
00227 debug_msg(1, "Project Parser: %s:%d : Ignored due to block being false.",
00228 parser.file.latin1(), parser.line_no);
00229 return TRUE;
00230 }
00231
00232 QString scope, var, op;
00233 QStringList val;
00234 #define SKIP_WS(d) while(*d && (*d == ' ' || *d == '\t')) d++
00235 const char *d = s.latin1();
00236 SKIP_WS(d);
00237 bool scope_failed = FALSE, else_line = FALSE, or_op=FALSE;
00238 int parens = 0, scope_count=0;
00239 while(*d) {
00240 if(!parens) {
00241 if(*d == '=')
00242 break;
00243 if(*d == '+' || *d == '-' || *d == '*' || *d == '~') {
00244 if(*(d+1) == '=') {
00245 break;
00246 } else if(*(d+1) == ' ') {
00247 const char *k = d + 1;
00248 SKIP_WS(k);
00249 if(*k == '=') {
00250 QString msg;
00251 qmake_error_msg(*d + "must be followed immediately by =");
00252 return FALSE;
00253 }
00254 }
00255 }
00256 }
00257
00258 if ( *d == '(' )
00259 ++parens;
00260 else if ( *d == ')' )
00261 --parens;
00262
00263 if(!parens && (*d == ':' || *d == '{' || *d == ')' || *d == '|')) {
00264 scope_count++;
00265 scope = var.stripWhiteSpace();
00266 if ( *d == ')' )
00267 scope += *d;
00268 var = "";
00269
00270 bool test = scope_failed;
00271 if(scope.lower() == "else") {
00272 if(scope_count != 1 || test_status == TestNone) {
00273 qmake_error_msg("Unexpected " + scope + " ('" + s + "')");
00274 return FALSE;
00275 }
00276 else_line = TRUE;
00277 test = (test_status == TestSeek);
00278 debug_msg(1, "Project Parser: %s:%d : Else%s %s.", parser.file.latin1(), parser.line_no,
00279 scope == "else" ? "" : QString(" (" + scope + ")").latin1(),
00280 test ? "considered" : "excluded");
00281 } else {
00282 QString comp_scope = scope;
00283 bool invert_test = (comp_scope.left(1) == "!");
00284 if(invert_test)
00285 comp_scope = comp_scope.right(comp_scope.length()-1);
00286 int lparen = comp_scope.find('(');
00287 if(or_op || !scope_failed) {
00288 if(lparen != -1) {
00289 int rparen = comp_scope.findRev(')');
00290 if(rparen == -1) {
00291 QCString error;
00292 error.sprintf("Function missing right paren: %s ('%s')",
00293 comp_scope.latin1(), s.latin1());
00294 qmake_error_msg(error);
00295 return FALSE;
00296 }
00297 QString func = comp_scope.left(lparen);
00298 test = doProjectTest(func, comp_scope.mid(lparen+1, rparen - lparen - 1), place);
00299 if ( *d == ')' && !*(d+1) ) {
00300 if(invert_test)
00301 test = !test;
00302 test_status = (test ? TestFound : TestSeek);
00303 return TRUE;
00304 }
00305 } else {
00306 test = isActiveConfig(comp_scope.stripWhiteSpace(), TRUE, &place);
00307 }
00308 if(invert_test)
00309 test = !test;
00310 }
00311 }
00312 if(!test && !scope_failed)
00313 debug_msg(1, "Project Parser: %s:%d : Test (%s) failed.", parser.file.latin1(),
00314 parser.line_no, scope.latin1());
00315 if(test == or_op)
00316 scope_failed = !test;
00317 or_op = (*d == '|');
00318 if(*d == '{') {
00319 if(!scope_failed)
00320 scope_flag |= (0x01 << (++scope_block));
00321 else
00322 scope_flag &= ~(0x01 << (++scope_block));
00323 debug_msg(1, "Project Parser: %s:%d : Entering block %d (%d).", parser.file.latin1(),
00324 parser.line_no, scope_block, !scope_failed);
00325 }
00326 } else if(!parens && *d == '}') {
00327 if(!scope_block) {
00328 warn_msg(WarnParser, "Possible braces mismatch %s:%d", parser.file.latin1(), parser.line_no);
00329 } else {
00330 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(),
00331 parser.line_no, scope_block);
00332 --scope_block;
00333 }
00334 } else {
00335 var += *d;
00336 }
00337 d++;
00338 }
00339 var = var.stripWhiteSpace();
00340 if(!scope_count || (scope_count == 1 && else_line))
00341 test_status = TestNone;
00342 else if(!else_line || test_status != TestFound)
00343 test_status = (scope_failed ? TestSeek : TestFound);
00344 if(scope_failed)
00345 return TRUE;
00346 if(!*d) {
00347 if(!var.stripWhiteSpace().isEmpty())
00348 qmake_error_msg("Parse Error ('" + s + "')");
00349 return var.isEmpty();
00350 }
00351
00352 SKIP_WS(d);
00353 for( ; *d && op.find('=') == -1; op += *(d++))
00354 ;
00355 op.replace(QRegExp("\\s"), "");
00356
00357 SKIP_WS(d);
00358 QString vals(d);
00359 int rbraces = vals.contains('}'), lbraces = vals.contains('{');
00360 if(scope_block && rbraces - lbraces == 1) {
00361 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(),
00362 parser.line_no, scope_block);
00363 test_status = ((scope_flag & (0x01 << scope_block)) ? TestFound : TestSeek);
00364 scope_block--;
00365 vals.truncate(vals.length()-1);
00366 } else if(rbraces != lbraces) {
00367 warn_msg(WarnParser, "Possible braces mismatch {%s} %s:%d",
00368 vals.latin1(), parser.file.latin1(), parser.line_no);
00369 }
00370 doVariableReplace(vals, place);
00371
00372 #undef SKIP_WS
00373
00374 if(!var.isEmpty() && Option::mkfile::do_preprocess) {
00375 static QString last_file("*none*");
00376 if(parser.file != last_file) {
00377 fprintf(stdout, "#file %s:%d\n", parser.file.latin1(), parser.line_no);
00378 last_file = parser.file;
00379 }
00380 fprintf(stdout, "%s %s %s\n", var.latin1(), op.latin1(), vals.latin1());
00381 }
00382 var = varMap(var);
00383
00384
00385 QStringList vallist = split_value_list(vals, (var == "DEPENDPATH" || var == "INCLUDEPATH"));
00386 if(!vallist.grep("=").isEmpty())
00387 warn_msg(WarnParser, "Detected possible line continuation: {%s} %s:%d",
00388 var.latin1(), parser.file.latin1(), parser.line_no);
00389
00390 QStringList &varlist = place[var];
00391 debug_msg(1, "Project Parser: %s:%d :%s: :%s: (%s)", parser.file.latin1(), parser.line_no,
00392 var.latin1(), op.latin1(), vallist.isEmpty() ? "" : vallist.join(" :: ").latin1());
00393
00394
00395 if(op == "~=") {
00396 if(vallist.count() != 1) {
00397 qmake_error_msg("~= operator only accepts one right hand paramater ('" +
00398 s + "')");
00399 return FALSE;
00400 }
00401 QString val(vallist.first());
00402 if(val.length() < 4 || val.at(0) != 's') {
00403 qmake_error_msg("~= operator only can handle s/// function ('" +
00404 s + "')");
00405 return FALSE;
00406 }
00407 QChar sep = val.at(1);
00408 QStringList func = QStringList::split(sep, val, TRUE);
00409 if(func.count() < 3 || func.count() > 4) {
00410 qmake_error_msg("~= operator only can handle s/// function ('" +
00411 s + "')");
00412 return FALSE;
00413 }
00414 bool global = FALSE, case_sense = TRUE;
00415 if(func.count() == 4) {
00416 global = func[3].find('g') != -1;
00417 case_sense = func[3].find('i') == -1;
00418 }
00419 QRegExp regexp(func[1], case_sense);
00420 for(QStringList::Iterator varit = varlist.begin();
00421 varit != varlist.end(); ++varit) {
00422 if((*varit).contains(regexp)) {
00423 (*varit) = (*varit).replace(regexp, func[2]);
00424 if(!global)
00425 break;
00426 }
00427 }
00428 } else {
00429 if(op == "=") {
00430 if(!varlist.isEmpty())
00431 warn_msg(WarnParser, "Operator=(%s) clears variables previously set: %s:%d",
00432 var.latin1(), parser.file.latin1(), parser.line_no);
00433 varlist.clear();
00434 }
00435 for(QStringList::Iterator valit = vallist.begin();
00436 valit != vallist.end(); ++valit) {
00437 if((*valit).isEmpty())
00438 continue;
00439 if((op == "*=" && !(*varlist.find((*valit)))) ||
00440 op == "=" || op == "+=")
00441 varlist.append((*valit));
00442 else if(op == "-=")
00443 varlist.remove((*valit));
00444 }
00445 }
00446 if(var == "REQUIRES")
00447 doProjectCheckReqs(vallist, place);
00448
00449 return TRUE;
00450 }
00451
00452 bool
00453 QMakeProject::read(const QString &file, QMap<QString, QStringList> &place)
00454 {
00455 parser_info pi = parser;
00456 reset();
00457
00458 QString filename = Option::fixPathToLocalOS(file);
00459 doVariableReplace(filename, place);
00460 bool ret = FALSE, using_stdin = FALSE;
00461 QFile qfile;
00462 if(!strcmp(filename, "-")) {
00463 qfile.setName("");
00464 ret = qfile.open(IO_ReadOnly, stdin);
00465 using_stdin = TRUE;
00466 } else {
00467 qfile.setName(filename);
00468 ret = qfile.open(IO_ReadOnly);
00469 }
00470 if ( ret ) {
00471 QTextStream t( &qfile );
00472 QString s, line;
00473 parser.file = filename;
00474 parser.line_no = 0;
00475 while ( !t.eof() ) {
00476 parser.line_no++;
00477 line = t.readLine().stripWhiteSpace();
00478 int prelen = line.length();
00479
00480 int hash_mark = line.find("#");
00481 if(hash_mark != -1)
00482 line = line.left(hash_mark);
00483 if(!line.isEmpty() && line.right(1) == "\\") {
00484 if (!line.startsWith("#")) {
00485 line.truncate(line.length() - 1);
00486 s += line + " ";
00487 }
00488 } else if(!line.isEmpty() || (line.isEmpty() && !prelen)) {
00489 if(s.isEmpty() && line.isEmpty())
00490 continue;
00491 if(!line.isEmpty())
00492 s += line;
00493 if(!s.isEmpty()) {
00494 if(!(ret = parse(s, place)))
00495 break;
00496 s = "";
00497 }
00498 }
00499 }
00500 if(!using_stdin)
00501 qfile.close();
00502 }
00503 parser = pi;
00504 if(scope_block != 0)
00505 warn_msg(WarnParser, "%s: Unterminated conditional at end of file.",
00506 file.latin1());
00507 return ret;
00508 }
00509
00510 bool
00511 QMakeProject::read(const QString &project, const QString &, uchar cmd)
00512 {
00513 pfile = project;
00514 return read(cmd);
00515 }
00516
00517 bool
00518 QMakeProject::read(uchar cmd)
00519 {
00520 if(cfile.isEmpty()) {
00521
00522 base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext;
00523 base_vars["QMAKE_EXT_H"] = Option::h_ext;
00524 if(!Option::user_template_prefix.isEmpty())
00525 base_vars["TEMPLATE_PREFIX"] = Option::user_template_prefix;
00526
00527 if(cmd & ReadCache && Option::mkfile::do_cache) {
00528 if(Option::mkfile::cachefile.isEmpty()) {
00529 QString dir = QDir::convertSeparators(Option::output_dir);
00530 while(!QFile::exists((Option::mkfile::cachefile = dir +
00531 QDir::separator() + ".qmake.cache"))) {
00532 dir = dir.left(dir.findRev(QDir::separator()));
00533 if(dir.isEmpty() || dir.find(QDir::separator()) == -1) {
00534 Option::mkfile::cachefile = "";
00535 break;
00536 }
00537 if(Option::mkfile::cachefile_depth == -1)
00538 Option::mkfile::cachefile_depth = 1;
00539 else
00540 Option::mkfile::cachefile_depth++;
00541 }
00542 }
00543 if(!Option::mkfile::cachefile.isEmpty()) {
00544 read(Option::mkfile::cachefile, cache);
00545 if(Option::mkfile::qmakespec.isEmpty() && !cache["QMAKESPEC"].isEmpty())
00546 Option::mkfile::qmakespec = cache["QMAKESPEC"].first();
00547 }
00548 }
00549 if(cmd & ReadConf) {
00550 QStringList mkspec_roots = qmake_mkspec_paths();
00551 if(Option::mkfile::qmakespec.isEmpty()) {
00552 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
00553 QString mkspec = (*it) + QDir::separator() + "default";
00554 if(QFile::exists(mkspec)) {
00555 Option::mkfile::qmakespec = mkspec;
00556 break;
00557 }
00558 }
00559 if(Option::mkfile::qmakespec.isEmpty()) {
00560 fprintf(stderr, "QMAKESPEC has not been set, so configuration cannot be deduced.\n");
00561 return FALSE;
00562 }
00563 }
00564
00565 if(QDir::isRelativePath(Option::mkfile::qmakespec)) {
00566 bool found_mkspec = FALSE;
00567 for(QStringList::Iterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
00568 QString mkspec = (*it) + QDir::separator() + Option::mkfile::qmakespec;
00569 if(QFile::exists(mkspec)) {
00570 found_mkspec = TRUE;
00571 Option::mkfile::qmakespec = mkspec;
00572 break;
00573 }
00574 }
00575 if(!found_mkspec) {
00576 fprintf(stderr, "Could not find mkspecs for your QMAKESPEC after trying:\n\t%s\n",
00577 mkspec_roots.join("\n\t").latin1());
00578 return FALSE;
00579 }
00580 }
00581
00582
00583 while(Option::mkfile::qmakespec.endsWith(QString(QChar(QDir::separator()))))
00584 Option::mkfile::qmakespec.truncate(Option::mkfile::qmakespec.length()-1);
00585 QString spec = Option::mkfile::qmakespec + QDir::separator() + "qmake.conf";
00586 if(!QFile::exists(spec) &&
00587 QFile::exists(Option::mkfile::qmakespec + QDir::separator() + "tmake.conf"))
00588 spec = Option::mkfile::qmakespec + QDir::separator() + "tmake.conf";
00589 debug_msg(1, "QMAKESPEC conf: reading %s", spec.latin1());
00590 if(!read(spec, base_vars)) {
00591 fprintf(stderr, "Failure to read QMAKESPEC conf file %s.\n", spec.latin1());
00592 return FALSE;
00593 }
00594 if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) {
00595 debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.latin1());
00596 read(Option::mkfile::cachefile, base_vars);
00597 }
00598 }
00599 if(cmd & ReadCmdLine) {
00600
00601 cfile = pfile;
00602 parser.line_no = 1;
00603 parser.file = "(internal)";
00604 reset();
00605 for(QStringList::Iterator it = Option::before_user_vars.begin();
00606 it != Option::before_user_vars.end(); ++it) {
00607 if(!parse((*it), base_vars)) {
00608 fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1());
00609 return FALSE;
00610 }
00611 parser.line_no++;
00612 }
00613 }
00614 }
00615
00616 vars = base_vars;
00617
00618 if(cmd & ReadProFile) {
00619 debug_msg(1, "Project file: reading %s", pfile.latin1());
00620 if(pfile != "-" && !QFile::exists(pfile) && !pfile.endsWith(".pro"))
00621 pfile += ".pro";
00622 if(!read(pfile, vars))
00623 return FALSE;
00624 }
00625
00626 if(cmd & ReadPostFiles) {
00627 const QStringList l = vars["QMAKE_POST_INCLUDE_FILES"];
00628 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
00629 read((*it), vars);
00630 }
00631
00632 if(cmd & ReadCmdLine) {
00633 parser.line_no = 1;
00634 parser.file = "(internal)";
00635 reset();
00636 for(QStringList::Iterator it = Option::after_user_vars.begin();
00637 it != Option::after_user_vars.end(); ++it) {
00638 if(!parse((*it), vars)) {
00639 fprintf(stderr, "Argument failed to parse: %s\n", (*it).latin1());
00640 return FALSE;
00641 }
00642 parser.line_no++;
00643 }
00644 }
00645
00646
00647 if(!Option::user_template.isEmpty()) {
00648 debug_msg(1, "Overriding TEMPLATE (%s) with: %s", vars["TEMPLATE"].first().latin1(),
00649 Option::user_template.latin1());
00650 vars["TEMPLATE"].clear();
00651 vars["TEMPLATE"].append(Option::user_template);
00652 }
00653
00654 QStringList &templ = vars["TEMPLATE"];
00655 if(templ.isEmpty())
00656 templ.append(QString("app"));
00657 else if(vars["TEMPLATE"].first().endsWith(".t"))
00658 templ = QStringList(templ.first().left(templ.first().length() - 2));
00659 if ( !Option::user_template_prefix.isEmpty() )
00660 templ.first().prepend(Option::user_template_prefix);
00661
00662 if(vars["TARGET"].isEmpty()) {
00663
00664
00665
00666 QString tmp = pfile;
00667 if(tmp.findRev('/') != -1)
00668 tmp = tmp.right( tmp.length() - tmp.findRev('/') - 1 );
00669 if(tmp.findRev('.') != -1)
00670 tmp = tmp.left(tmp.findRev('.'));
00671 vars["TARGET"].append(tmp);
00672 }
00673
00674 QString test_version = getenv("QTESTVERSION");
00675 if (!test_version.isEmpty()) {
00676 QString s = vars["TARGET"].first();
00677 if (s == "qt" || s == "qt-mt" || s == "qte" || s == "qte-mt") {
00678 QString &ver = vars["VERSION"].first();
00679
00680 if (ver != "" && ver != test_version) {
00681 ver = test_version;
00682 fprintf(stderr,"Changed QT version number to " + test_version + "!\n");
00683 }
00684 }
00685 }
00686 return TRUE;
00687 }
00688
00689 bool
00690 QMakeProject::isActiveConfig(const QString &x, bool regex, QMap<QString, QStringList> *place)
00691 {
00692 if(x.isEmpty())
00693 return TRUE;
00694
00695 if((Option::target_mode == Option::TARG_MACX_MODE || Option::target_mode == Option::TARG_QNX6_MODE ||
00696 Option::target_mode == Option::TARG_UNIX_MODE) && x == "unix")
00697 return TRUE;
00698 else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx")
00699 return TRUE;
00700 else if(Option::target_mode == Option::TARG_QNX6_MODE && x == "qnx6")
00701 return TRUE;
00702 else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9")
00703 return TRUE;
00704 else if((Option::target_mode == Option::TARG_MAC9_MODE || Option::target_mode == Option::TARG_MACX_MODE) &&
00705 x == "mac")
00706 return TRUE;
00707 else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32")
00708 return TRUE;
00709
00710
00711 QRegExp re(x, FALSE, TRUE);
00712 QString spec = Option::mkfile::qmakespec.right(Option::mkfile::qmakespec.length() -
00713 (Option::mkfile::qmakespec.findRev(QDir::separator())+1));
00714 if((regex && re.exactMatch(spec)) || (!regex && spec == x))
00715 return TRUE;
00716 #ifdef Q_OS_UNIX
00717 else if(spec == "default") {
00718 static char *buffer = NULL;
00719 if(!buffer)
00720 buffer = (char *)malloc(1024);
00721 int l = readlink(Option::mkfile::qmakespec, buffer, 1024);
00722 if(l != -1) {
00723 buffer[l] = '\0';
00724 QString r = buffer;
00725 if(r.findRev('/') != -1)
00726 r = r.mid(r.findRev('/') + 1);
00727 if((regex && re.exactMatch(r)) || (!regex && r == x))
00728 return TRUE;
00729 }
00730 }
00731 #endif
00732
00733
00734 QStringList &configs = (place ? (*place)["CONFIG"] : vars["CONFIG"]);
00735 for(QStringList::Iterator it = configs.begin(); it != configs.end(); ++it) {
00736 if((regex && re.exactMatch((*it))) || (!regex && (*it) == x))
00737 if(re.exactMatch((*it)))
00738 return TRUE;
00739 }
00740 return FALSE;
00741 }
00742
00743 bool
00744 QMakeProject::doProjectTest(const QString& func, const QString ¶ms, QMap<QString, QStringList> &place)
00745 {
00746 QStringList args = split_arg_list(params);
00747 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) {
00748 QString tmp = (*arit).stripWhiteSpace();
00749 if((tmp[0] == '\'' || tmp[0] == '"') && tmp.right(1) == tmp.left(1))
00750 tmp = tmp.mid(1, tmp.length() - 2);
00751 }
00752 return doProjectTest(func.stripWhiteSpace(), args, place);
00753 }
00754
00755 bool
00756 QMakeProject::doProjectTest(const QString& func, QStringList args, QMap<QString, QStringList> &place)
00757 {
00758 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) {
00759 (*arit) = (*arit).stripWhiteSpace();
00760 doVariableReplace((*arit), place);
00761 }
00762 debug_msg(1, "Running project test: %s( %s )", func.latin1(), args.join("::").latin1());
00763
00764 if(func == "requires") {
00765 return doProjectCheckReqs(args, place);
00766 } else if(func == "equals") {
00767 if(args.count() != 2) {
00768 fprintf(stderr, "%s:%d: equals(variable, value) requires two arguments.\n", parser.file.latin1(),
00769 parser.line_no);
00770 return FALSE;
00771 }
00772 QString value = args[1];
00773 if((value.left(1) == "\"" || value.left(1) == "'") && value.right(1) == value.left(1))
00774 value = value.mid(1, value.length()-2);
00775 return vars[args[0]].join(" ") == value;
00776 } else if(func == "exists") {
00777 if(args.count() != 1) {
00778 fprintf(stderr, "%s:%d: exists(file) requires one argument.\n", parser.file.latin1(),
00779 parser.line_no);
00780 return FALSE;
00781 }
00782 QString file = args.first();
00783 file = Option::fixPathToLocalOS(file);
00784 doVariableReplace(file, place);
00785
00786 if(QFile::exists(file))
00787 return TRUE;
00788
00789 QString dirstr = QDir::currentDirPath();
00790 int slsh = file.findRev(Option::dir_sep);
00791 if(slsh != -1) {
00792 dirstr = file.left(slsh+1);
00793 file = file.right(file.length() - slsh - 1);
00794 }
00795 QDir dir(dirstr, file);
00796 return dir.count() != 0;
00797 } else if(func == "system") {
00798 if(args.count() != 1) {
00799 fprintf(stderr, "%s:%d: system(exec) requires one argument.\n", parser.file.latin1(),
00800 parser.line_no);
00801 return FALSE;
00802 }
00803 return system(args.first().latin1()) == 0;
00804 } else if(func == "contains") {
00805 if(args.count() != 2) {
00806 fprintf(stderr, "%s:%d: contains(var, val) requires two arguments.\n", parser.file.latin1(),
00807 parser.line_no);
00808 return FALSE;
00809 }
00810 QRegExp regx(args[1]);
00811 QStringList &l = place[args[0]];
00812 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
00813 if(regx.exactMatch((*it)))
00814 return TRUE;
00815 }
00816 return FALSE;
00817 } else if(func == "infile") {
00818 if(args.count() < 2 || args.count() > 3) {
00819 fprintf(stderr, "%s:%d: infile(file, var, val) requires at least 2 arguments.\n",
00820 parser.file.latin1(), parser.line_no);
00821 return FALSE;
00822 }
00823 QMakeProject proj;
00824 QString file = args[0];
00825 doVariableReplace(file, place);
00826 fixEnvVariables(file);
00827 int di = file.findRev(Option::dir_sep);
00828 QDir sunworkshop42workaround = QDir::current();
00829 QString oldpwd = sunworkshop42workaround.currentDirPath();
00830 if(di != -1) {
00831 if(!QDir::setCurrent(file.left(file.findRev(Option::dir_sep)))) {
00832 fprintf(stderr, "Cannot find directory: %s\n", file.left(di).latin1());
00833 return FALSE;
00834 }
00835 file = file.right(file.length() - di - 1);
00836 }
00837 parser_info pi = parser;
00838 bool ret = !proj.read(file, oldpwd);
00839 parser = pi;
00840 if(ret) {
00841 fprintf(stderr, "Error processing project file: %s\n", file.latin1());
00842 QDir::setCurrent(oldpwd);
00843 return FALSE;
00844 }
00845 if(args.count() == 2) {
00846 ret = !proj.isEmpty(args[1]);
00847 } else {
00848 QRegExp regx(args[2]);
00849 QStringList &l = proj.values(args[1]);
00850 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
00851 if(regx.exactMatch((*it))) {
00852 ret = TRUE;
00853 break;
00854 }
00855 }
00856 }
00857 QDir::setCurrent(oldpwd);
00858 return ret;
00859 } else if(func == "count") {
00860 if(args.count() != 2) {
00861 fprintf(stderr, "%s:%d: count(var, count) requires two arguments.\n", parser.file.latin1(),
00862 parser.line_no);
00863 return FALSE;
00864 }
00865 return vars[args[0]].count() == args[1].toUInt();
00866 } else if(func == "isEmpty") {
00867 if(args.count() != 1) {
00868 fprintf(stderr, "%s:%d: isEmpty(var) requires one argument.\n", parser.file.latin1(),
00869 parser.line_no);
00870 return FALSE;
00871 }
00872 return vars[args[0]].isEmpty();
00873 } else if(func == "include" || func == "load") {
00874 QString seek_var;
00875 if(args.count() == 2 && func == "include") {
00876 seek_var = args[1];
00877 } else if(args.count() != 1) {
00878 QString func_desc = "include(file)";
00879 if(func == "load")
00880 func_desc = "load(feature)";
00881 fprintf(stderr, "%s:%d: %s requires one argument.\n", parser.file.latin1(),
00882 parser.line_no, func_desc.latin1());
00883 return FALSE;
00884 }
00885
00886 QString file = args.first();
00887 file = Option::fixPathToLocalOS(file);
00888 file.replace("\"", "");
00889 doVariableReplace(file, place);
00890 if(func == "load") {
00891 if(!file.endsWith(Option::prf_ext))
00892 file += Option::prf_ext;
00893 if(file.find(Option::dir_sep) == -1 || !QFile::exists(file)) {
00894 bool found = FALSE;
00895 const QString concat = QDir::separator() + QString("mkspecs") +
00896 QDir::separator() + QString("features");
00897 QStringList feature_roots;
00898 if(const char *mkspec_path = getenv("QMAKEFEATURES")) {
00899 #ifdef Q_OS_WIN
00900 QStringList lst = QStringList::split(';', mkspec_path);
00901 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it)
00902 feature_roots += QStringList::split(':', (*it));
00903 #else
00904 feature_roots += QStringList::split(':', mkspec_path);
00905 #endif
00906 }
00907 if(const char *qmakepath = getenv("QMAKEPATH")) {
00908 #ifdef Q_OS_WIN
00909 QStringList lst = QStringList::split(';', qmakepath);
00910 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it) {
00911 QStringList lst2 = QStringList::split(':', (*it));
00912 for(QStringList::Iterator it2 = lst2.begin(); it2 != lst2.end(); ++it2)
00913 feature_roots << ((*it2) + concat);
00914 }
00915 #else
00916 QStringList lst = QStringList::split(':', qmakepath);
00917 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it)
00918 feature_roots << ((*it) + concat);
00919 #endif
00920 }
00921 feature_roots << Option::mkfile::qmakespec;
00922 if(const char *qtdir = getenv("QTDIR"))
00923 feature_roots << (qtdir + concat);
00924 #ifdef QT_INSTALL_PREFIX
00925 feature_roots << (QT_INSTALL_PREFIX + concat);
00926 #endif
00927 #if defined(HAVE_QCONFIG_CPP)
00928 feature_roots << (qInstallPath() + concat);
00929 #endif
00930 #ifdef QT_INSTALL_DATA
00931 feature_roots << (QT_INSTALL_DATA + concat);
00932 #endif
00933 #if defined(HAVE_QCONFIG_CPP)
00934 feature_roots << (qInstallPathData() + concat);
00935 #endif
00936 for(QStringList::Iterator it = feature_roots.begin(); it != feature_roots.end(); ++it) {
00937 QString prf = (*it) + QDir::separator() + file;
00938 if(QFile::exists(prf)) {
00939 found = TRUE;
00940 file = prf;
00941 break;
00942 }
00943 }
00944 if(!found) {
00945 printf("Project LOAD(): Feature %s cannot be found.\n", args.first().latin1());
00946 exit(3);
00947 }
00948 }
00949 }
00950 if(QDir::isRelativePath(file)) {
00951 QStringList include_roots;
00952 include_roots << Option::output_dir;
00953 QString pfilewd = QFileInfo(parser.file).dirPath();
00954 if(pfilewd.isEmpty())
00955 include_roots << pfilewd;
00956 if(Option::output_dir != QDir::currentDirPath())
00957 include_roots << QDir::currentDirPath();
00958 for(QStringList::Iterator it = include_roots.begin(); it != include_roots.end(); ++it) {
00959 if(QFile::exists((*it) + QDir::separator() + file)) {
00960 file = (*it) + QDir::separator() + file;
00961 break;
00962 }
00963 }
00964 }
00965
00966 if(Option::mkfile::do_preprocess)
00967 fprintf(stderr, "#switching file %s(%s) - %s:%d\n", func.latin1(), file.latin1(),
00968 parser.file.latin1(), parser.line_no);
00969 debug_msg(1, "Project Parser: %s'ing file %s.", func.latin1(), file.latin1());
00970 QString orig_file = file;
00971 int di = file.findRev(Option::dir_sep);
00972 QDir sunworkshop42workaround = QDir::current();
00973 QString oldpwd = sunworkshop42workaround.currentDirPath();
00974 if(di != -1) {
00975 if(!QDir::setCurrent(file.left(file.findRev(Option::dir_sep)))) {
00976 fprintf(stderr, "Cannot find directory: %s\n", file.left(di).latin1());
00977 return FALSE;
00978 }
00979 file = file.right(file.length() - di - 1);
00980 }
00981 parser_info pi = parser;
00982 int sb = scope_block;
00983 int sf = scope_flag;
00984 TestStatus sc = test_status;
00985 bool r = FALSE;
00986 if(!seek_var.isNull()) {
00987 QMap<QString, QStringList> tmp;
00988 if((r = read(file.latin1(), tmp)))
00989 place[seek_var] += tmp[seek_var];
00990 } else {
00991 r = read(file.latin1(), place);
00992 }
00993 if(r)
00994 vars["QMAKE_INTERNAL_INCLUDED_FILES"].append(orig_file);
00995 else
00996 warn_msg(WarnParser, "%s:%d: Failure to include file %s.",
00997 pi.file.latin1(), pi.line_no, orig_file.latin1());
00998 parser = pi;
00999 test_status = sc;
01000 scope_flag = sf;
01001 scope_block = sb;
01002 QDir::setCurrent(oldpwd);
01003 return r;
01004 } else if(func == "error" || func == "message") {
01005 if(args.count() != 1) {
01006 fprintf(stderr, "%s:%d: %s(message) requires one argument.\n", parser.file.latin1(),
01007 parser.line_no, func.latin1());
01008 return FALSE;
01009 }
01010 QString msg = args.first();
01011 if((msg.startsWith("\"") || msg.startsWith("'")) && msg.endsWith(msg.left(1)))
01012 msg = msg.mid(1, msg.length()-2);
01013 msg.replace(QString("${QMAKE_FILE}"), parser.file.latin1());
01014 msg.replace(QString("${QMAKE_LINE_NUMBER}"), QString::number(parser.line_no));
01015 msg.replace(QString("${QMAKE_DATE}"), QDateTime::currentDateTime().toString());
01016 doVariableReplace(msg, place);
01017 fixEnvVariables(msg);
01018 fprintf(stderr, "Project %s: %s\n", func.upper().latin1(), msg.latin1());
01019 if(func == "message")
01020 return TRUE;
01021 exit(2);
01022 } else {
01023 fprintf(stderr, "%s:%d: Unknown test function: %s\n", parser.file.latin1(), parser.line_no,
01024 func.latin1());
01025 }
01026 return FALSE;
01027 }
01028
01029 bool
01030 QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringList> &place)
01031 {
01032 bool ret = FALSE;
01033 for(QStringList::ConstIterator it = deps.begin(); it != deps.end(); ++it) {
01034 QString chk = (*it);
01035 if(chk.isEmpty())
01036 continue;
01037 bool invert_test = (chk.left(1) == "!");
01038 if(invert_test)
01039 chk = chk.right(chk.length() - 1);
01040
01041 bool test;
01042 int lparen = chk.find('(');
01043 if(lparen != -1) {
01044 int rparen = chk.findRev(')');
01045 if(rparen == -1) {
01046 QCString error;
01047 error.sprintf("Function (in REQUIRES) missing right paren: %s", chk.latin1());
01048 qmake_error_msg(error);
01049 } else {
01050 QString func = chk.left(lparen);
01051 test = doProjectTest(func, chk.mid(lparen+1, rparen - lparen - 1), place);
01052 }
01053 } else {
01054 test = isActiveConfig(chk, TRUE, &place);
01055 }
01056 if(invert_test) {
01057 chk.prepend("!");
01058 test = !test;
01059 }
01060 if(!test) {
01061 debug_msg(1, "Project Parser: %s:%d Failed test: REQUIRES = %s",
01062 parser.file.latin1(), parser.line_no, chk.latin1());
01063 place["QMAKE_FAILED_REQUIREMENTS"].append(chk);
01064 ret = FALSE;
01065 }
01066 }
01067 return ret;
01068 }
01069
01070
01071 QString
01072 QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &place)
01073 {
01074 for(int var_begin, var_last=0; (var_begin = str.find("$$", var_last)) != -1; var_last = var_begin) {
01075 if(var_begin >= (int)str.length() + 2) {
01076 break;
01077 } else if(var_begin != 0 && str[var_begin-1] == '\\') {
01078 str.replace(var_begin-1, 1, "");
01079 var_begin += 1;
01080 continue;
01081 }
01082
01083 int var_incr = var_begin + 2;
01084 bool in_braces = FALSE, as_env = FALSE, as_prop = FALSE;
01085 if(str[var_incr] == '{') {
01086 in_braces = TRUE;
01087 var_incr++;
01088 while(var_incr < (int)str.length() &&
01089 (str[var_incr] == ' ' || str[var_incr] == '\t' || str[var_incr] == '\n'))
01090 var_incr++;
01091 }
01092 if(str[var_incr] == '(') {
01093 as_env = TRUE;
01094 var_incr++;
01095 } else if(str[var_incr] == '[') {
01096 as_prop = TRUE;
01097 var_incr++;
01098 }
01099 QString val, args;
01100 while(var_incr < (int)str.length() &&
01101 (str[var_incr].isLetter() || str[var_incr].isNumber() || str[var_incr] == '.' || str[var_incr] == '_'))
01102 val += str[var_incr++];
01103 if(as_env) {
01104 if(str[var_incr] != ')') {
01105 var_incr++;
01106 warn_msg(WarnParser, "%s:%d: Unterminated env-variable replacement '%s' (%s)",
01107 parser.file.latin1(), parser.line_no,
01108 str.mid(var_begin, QMAX(var_incr - var_begin,
01109 (int)str.length())).latin1(), str.latin1());
01110 var_begin += var_incr;
01111 continue;
01112 }
01113 var_incr++;
01114 } else if(as_prop) {
01115 if(str[var_incr] != ']') {
01116 var_incr++;
01117 warn_msg(WarnParser, "%s:%d: Unterminated prop-variable replacement '%s' (%s)",
01118 parser.file.latin1(), parser.line_no,
01119 str.mid(var_begin, QMAX(var_incr - var_begin, int(str.length()))).latin1(), str.latin1());
01120 var_begin += var_incr;
01121 continue;
01122 }
01123 var_incr++;
01124 } else if(str[var_incr] == '(') {
01125 for(int parens = 0; var_incr < (int)str.length(); var_incr++) {
01126 if(str[var_incr] == '(') {
01127 parens++;
01128 if(parens == 1)
01129 continue;
01130 } else if(str[var_incr] == ')') {
01131 parens--;
01132 if(!parens) {
01133 var_incr++;
01134 break;
01135 }
01136 }
01137 args += str[var_incr];
01138 }
01139 }
01140 if(var_incr > (int)str.length() || (in_braces && str[var_incr] != '}')) {
01141 var_incr++;
01142 warn_msg(WarnParser, "%s:%d: Unterminated variable replacement '%s' (%s)",
01143 parser.file.latin1(), parser.line_no,
01144 str.mid(var_begin, QMAX(var_incr - var_begin,
01145 (int)str.length())).latin1(), str.latin1());
01146 var_begin += var_incr;
01147 continue;
01148 } else if(in_braces) {
01149 var_incr++;
01150 }
01151
01152 QString replacement;
01153 if(as_env) {
01154 replacement = getenv(val);
01155 } else if(as_prop) {
01156 if(prop)
01157 replacement = prop->value(val);
01158 } else if(args.isEmpty()) {
01159 if(val.left(1) == ".")
01160 replacement = "";
01161 else if(val == "LITERAL_WHITESPACE")
01162 replacement = "\t";
01163 else if(val == "LITERAL_DOLLAR")
01164 replacement = "$";
01165 else if(val == "LITERAL_HASH")
01166 replacement = "#";
01167 else if(val == "PWD")
01168 replacement = QDir::currentDirPath();
01169 else if(val == "DIR_SEPARATOR")
01170 replacement = Option::dir_sep;
01171 else
01172 replacement = place[varMap(val)].join(" ");
01173 } else {
01174 QStringList arg_list = split_arg_list(doVariableReplace(args, place));
01175 debug_msg(1, "Running function: %s( %s )", val.latin1(), arg_list.join("::").latin1());
01176 if(val.lower() == "member") {
01177 if(arg_list.count() < 1 || arg_list.count() > 3) {
01178 fprintf(stderr, "%s:%d: member(var, start, end) requires three arguments.\n",
01179 parser.file.latin1(), parser.line_no);
01180 } else {
01181 const QStringList &var = place[varMap(arg_list.first())];
01182 int start = 0;
01183 if(arg_list.count() >= 2)
01184 start = arg_list[1].toInt();
01185 if(start < 0)
01186 start += int(var.count());
01187 int end = start;
01188 if(arg_list.count() == 3)
01189 end = arg_list[2].toInt();
01190 if(end < 0)
01191 end += int(var.count());
01192 if(end < start)
01193 end = start;
01194 for(int i = start; i <= end && (int)var.count() >= i; i++) {
01195 if(!replacement.isEmpty())
01196 replacement += " ";
01197 replacement += var[i];
01198 }
01199 }
01200 } else if(val.lower() == "fromfile") {
01201 if(arg_list.count() != 2) {
01202 fprintf(stderr, "%s:%d: fromfile(file, variable) requires two arguments.\n",
01203 parser.file.latin1(), parser.line_no);
01204 } else {
01205 QString file = arg_list[0];
01206 file = Option::fixPathToLocalOS(file);
01207 file.replace("\"", "");
01208
01209 if(QDir::isRelativePath(file)) {
01210 QStringList include_roots;
01211 include_roots << Option::output_dir;
01212 QString pfilewd = QFileInfo(parser.file).dirPath();
01213 if(pfilewd.isEmpty())
01214 include_roots << pfilewd;
01215 if(Option::output_dir != QDir::currentDirPath())
01216 include_roots << QDir::currentDirPath();
01217 for(QStringList::Iterator it = include_roots.begin(); it != include_roots.end(); ++it) {
01218 if(QFile::exists((*it) + QDir::separator() + file)) {
01219 file = (*it) + QDir::separator() + file;
01220 break;
01221 }
01222 }
01223 }
01224 QString orig_file = file;
01225 int di = file.findRev(Option::dir_sep);
01226 QDir sunworkshop42workaround = QDir::current();
01227 QString oldpwd = sunworkshop42workaround.currentDirPath();
01228 if(di != -1 && QDir::setCurrent(file.left(file.findRev(Option::dir_sep))))
01229 file = file.right(file.length() - di - 1);
01230 parser_info pi = parser;
01231 int sb = scope_block;
01232 int sf = scope_flag;
01233 TestStatus sc = test_status;
01234 QMap<QString, QStringList> tmp;
01235 bool r = read(file.latin1(), tmp);
01236 if(r) {
01237 replacement = tmp[arg_list[1]].join(" ");
01238 vars["QMAKE_INTERNAL_INCLUDED_FILES"].append(orig_file);
01239 } else {
01240 warn_msg(WarnParser, "%s:%d: Failure to include file %s.",
01241 pi.file.latin1(), pi.line_no, orig_file.latin1());
01242 }
01243 parser = pi;
01244 test_status = sc;
01245 scope_flag = sf;
01246 scope_block = sb;
01247 QDir::setCurrent(oldpwd);
01248 }
01249 } else if(val.lower() == "eval") {
01250 for(QStringList::ConstIterator arg_it = arg_list.begin();
01251 arg_it != arg_list.end(); ++arg_it) {
01252 if(!replacement.isEmpty())
01253 replacement += " ";
01254 replacement += place[(*arg_it)].join(" ");
01255 }
01256 } else if(val.lower() == "list") {
01257 static int x = 0;
01258 replacement.sprintf(".QMAKE_INTERNAL_TMP_VAR_%d", x++);
01259 QStringList &lst = (*((QMap<QString, QStringList>*)&place))[replacement];
01260 lst.clear();
01261 for(QStringList::ConstIterator arg_it = arg_list.begin();
01262 arg_it != arg_list.end(); ++arg_it)
01263 lst += split_value_list((*arg_it));
01264 } else if(val.lower() == "join") {
01265 if(arg_list.count() < 1 || arg_list.count() > 4) {
01266 fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four"
01267 "arguments.\n", parser.file.latin1(), parser.line_no);
01268 } else {
01269 QString glue, before, after;
01270 if(arg_list.count() >= 2)
01271 glue = arg_list[1].replace("\"", "" );
01272 if(arg_list.count() >= 3)
01273 before = arg_list[2].replace("\"", "" );
01274 if(arg_list.count() == 4)
01275 after = arg_list[3].replace("\"", "" );
01276 const QStringList &var = place[varMap(arg_list.first())];
01277 if(!var.isEmpty())
01278 replacement = before + var.join(glue) + after;
01279 }
01280 } else if(val.lower() == "split") {
01281 if(arg_list.count() < 2 || arg_list.count() > 3) {
01282 fprintf(stderr, "%s:%d split(var, sep, join) requires three arguments\n",
01283 parser.file.latin1(), parser.line_no);
01284 } else {
01285 QString sep = arg_list[1], join = " ";
01286 if(arg_list.count() == 3)
01287 join = arg_list[2];
01288 QStringList var = place[varMap(arg_list.first())];
01289 for(QStringList::Iterator vit = var.begin(); vit != var.end(); ++vit) {
01290 QStringList lst = QStringList::split(sep, (*vit));
01291 for(QStringList::Iterator spltit = lst.begin(); spltit != lst.end(); ++spltit) {
01292 if(!replacement.isEmpty())
01293 replacement += join;
01294 replacement += (*spltit);
01295 }
01296 }
01297 }
01298 } else if(val.lower() == "find") {
01299 if(arg_list.count() != 2) {
01300 fprintf(stderr, "%s:%d find(var, str) requires two arguments\n",
01301 parser.file.latin1(), parser.line_no);
01302 } else {
01303 QRegExp regx(arg_list[1]);
01304 const QStringList &var = place[varMap(arg_list.first())];
01305 for(QStringList::ConstIterator vit = var.begin();
01306 vit != var.end(); ++vit) {
01307 if(regx.search(*vit) != -1) {
01308 if(!replacement.isEmpty())
01309 replacement += " ";
01310 replacement += (*vit);
01311 }
01312 }
01313 }
01314 } else if(val.lower() == "system") {
01315 if(arg_list.count() != 1) {
01316 fprintf(stderr, "%s:%d system(execut) requires one argument\n",
01317 parser.file.latin1(), parser.line_no);
01318 } else {
01319 char buff[256];
01320 FILE *proc = QT_POPEN(arg_list.join(" ").latin1(), "r");
01321 while(proc && !feof(proc)) {
01322 int read_in = int(fread(buff, 1, 255, proc));
01323 if(!read_in)
01324 break;
01325 for(int i = 0; i < read_in; i++) {
01326 if(buff[i] == '\n' || buff[i] == '\t')
01327 buff[i] = ' ';
01328 }
01329 buff[read_in] = '\0';
01330 replacement += buff;
01331 }
01332 }
01333 } else if(val.lower() == "files") {
01334 if(arg_list.count() != 1) {
01335 fprintf(stderr, "%s:%d files(pattern) requires one argument\n",
01336 parser.file.latin1(), parser.line_no);
01337 } else {
01338 QString dir, regex = arg_list[0];
01339 regex = Option::fixPathToLocalOS(regex);
01340 regex.replace("\"", "");
01341 if(regex.findRev(QDir::separator()) != -1) {
01342 dir = regex.left(regex.findRev(QDir::separator()) + 1);
01343 regex = regex.right(regex.length() - dir.length());
01344 }
01345 QDir d(dir, regex);
01346 for(int i = 0; i < (int)d.count(); i++) {
01347 if(!replacement.isEmpty())
01348 replacement += " ";
01349 replacement += dir + d[i];
01350 }
01351 }
01352 } else if(val.lower() == "prompt") {
01353 if(arg_list.count() != 1) {
01354 fprintf(stderr, "%s:%d prompt(question) requires one argument\n",
01355 parser.file.latin1(), parser.line_no);
01356 } else if(projectFile() == "-") {
01357 fprintf(stderr, "%s:%d prompt(question) cannot be used when '-o -' is used.\n",
01358 parser.file.latin1(), parser.line_no);
01359 } else {
01360 QString msg = arg_list.first();
01361 if((msg.startsWith("\"") || msg.startsWith("'")) && msg.endsWith(msg.left(1)))
01362 msg = msg.mid(1, msg.length()-2);
01363 msg.replace(QString("${QMAKE_FILE}"), parser.file.latin1());
01364 msg.replace(QString("${QMAKE_LINE_NUMBER}"), QString::number(parser.line_no));
01365 msg.replace(QString("${QMAKE_DATE}"), QDateTime::currentDateTime().toString());
01366 doVariableReplace(msg, place);
01367 fixEnvVariables(msg);
01368 if(!msg.endsWith("?"))
01369 msg += "?";
01370 fprintf(stderr, "Project %s: %s ", val.upper().latin1(), msg.latin1());
01371
01372 QFile qfile;
01373 if(qfile.open(IO_ReadOnly, stdin)) {
01374 QTextStream t(&qfile);
01375 replacement = t.readLine();
01376 }
01377 }
01378 } else {
01379 fprintf(stderr, "%s:%d: Unknown replace function: %s\n",
01380 parser.file.latin1(), parser.line_no, val.latin1());
01381 }
01382 }
01383
01384 int mlen = var_incr - var_begin;
01385 debug_msg(2, "Project Parser [var replace]: '%s' :: %s -> %s", str.latin1(),
01386 str.mid(var_begin, mlen).latin1(), replacement.latin1());
01387 str.replace(var_begin, mlen, replacement);
01388 var_begin += replacement.length();
01389 }
01390 return str;
01391 }