summaryrefslogtreecommitdiff
path: root/qmake/project.cpp
Unidiff
Diffstat (limited to 'qmake/project.cpp') (more/less context) (show whitespace changes)
-rw-r--r--qmake/project.cpp291
1 files changed, 187 insertions, 104 deletions
diff --git a/qmake/project.cpp b/qmake/project.cpp
index 44eb503..834823d 100644
--- a/qmake/project.cpp
+++ b/qmake/project.cpp
@@ -63,15 +63,20 @@ static void qmake_error_msg(const char *msg)
63 fprintf(stderr, "%s:%d: %s\n", parser.file.latin1(), parser.line_no, msg); 63 fprintf(stderr, "%s:%d: %s\n", parser.file.latin1(), parser.line_no, msg);
64} 64}
65 65
66static QString varMap(const QString &x) 66static QString varMap(const QString &x)
67{ 67{
68 QString ret(x); 68 QString ret(x);
69 ret.replace(QRegExp("^TMAKE"), "QMAKE"); 69 if(ret.startsWith("TMAKE")) //tmake no more!
70 ret = "QMAKE" + ret.mid(5);
70 if(ret == "INTERFACES") 71 if(ret == "INTERFACES")
71 ret = "FORMS"; 72 ret = "FORMS";
73 if(ret == "QMAKE_POST_BUILD")
74 ret = "QMAKE_POST_LINK";
75 if(ret == "TARGETDEPS")
76 ret = "POST_TARGETDEPS";
72 return ret; 77 return ret;
73} 78}
74 79
75static QStringList split_arg_list(const QString &params) 80static QStringList split_arg_list(const QString &params)
76{ 81{
77 QStringList args; 82 QStringList args;
@@ -119,16 +124,18 @@ static QStringList split_value_list(const QString &vals, bool do_semicolon=FALSE
119 124
120QMakeProject::QMakeProject() 125QMakeProject::QMakeProject()
121{ 126{
122} 127}
123 128
124bool 129bool
125QMakeProject::parse(QString t, QMap<QString, QStringList> &place) 130QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place)
126{ 131{
127 QString s = t.simplifyWhiteSpace(); 132 QString s = t.simplifyWhiteSpace();
128 s.replace(QRegExp("#.*$"), ""); /* bye comments */ 133 int hash_mark = s.find('#');
134 if(hash_mark != -1) //good bye comments
135 s = s.left(hash_mark);
129 if(s.isEmpty()) /* blank_line */ 136 if(s.isEmpty()) /* blank_line */
130 return TRUE; 137 return TRUE;
131 138
132 if(s.stripWhiteSpace().left(1) == "}") { 139 if(s.stripWhiteSpace().left(1) == "}") {
133 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(), 140 debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.latin1(),
134 parser.line_no, scope_block); 141 parser.line_no, scope_block);
@@ -151,26 +158,30 @@ QMakeProject::parse(QString t, QMap<QString, QStringList> &place)
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) {
166 if(*d == '=')
167 break;
168 if(*d == '+' || *d == '-' || *d == '*' || *d == '~') {
159 if(*(d+1) == '=') { 169 if(*(d+1) == '=') {
160 break; 170 break;
161 } else if(*(d+1) == ' ') { 171 } else if(*(d+1) == ' ') {
162 const char *k = d + 1; 172 const char *k = d + 1;
163 SKIP_WS(k); 173 SKIP_WS(k);
164 if(*k == '=') { 174 if(*k == '=') {
165 QString msg; 175 QString msg;
166 qmake_error_msg(*d + "must be followed immediatly by ="); 176 qmake_error_msg(*d + "must be followed immediately by =");
167 return FALSE; 177 return FALSE;
168 } 178 }
169 } 179 }
170 } 180 }
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
@@ -214,13 +225,13 @@ QMakeProject::parse(QString t, QMap<QString, QStringList> &place)
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)
@@ -352,42 +363,46 @@ QMakeProject::parse(QString t, QMap<QString, QStringList> &place)
352 doProjectCheckReqs(vallist, place); 363 doProjectCheckReqs(vallist, place);
353 364
354 return TRUE; 365 return TRUE;
355} 366}
356 367
357bool 368bool
358QMakeProject::read(QString file, QMap<QString, QStringList> &place) 369QMakeProject::read(const QString &file, QMap<QString, QStringList> &place)
359{ 370{
360 parser_info pi = parser; 371 parser_info pi = parser;
361 /* scope blocks start at true */ 372 /* scope blocks start at true */
362 test_status = TestNone; 373 test_status = TestNone;
363 scope_flag = 0x01; 374 scope_flag = 0x01;
364 scope_block = 0; 375 scope_block = 0;
365 376
366 file = Option::fixPathToLocalOS(file); 377 QString filename = Option::fixPathToLocalOS(file);
367 doVariableReplace(file, place); 378 doVariableReplace(filename, place);
368 bool ret = FALSE, using_stdin = FALSE; 379 bool ret = FALSE, using_stdin = FALSE;
369 QFile qfile; 380 QFile qfile;
370 if(!strcmp(file, "-")) { 381 if(!strcmp(filename, "-")) {
371 qfile.setName(""); 382 qfile.setName("");
372 ret = qfile.open(IO_ReadOnly, stdin); 383 ret = qfile.open(IO_ReadOnly, stdin);
373 using_stdin = TRUE; 384 using_stdin = TRUE;
374 } else { 385 } else {
375 qfile.setName(file); 386 qfile.setName(filename);
376 ret = qfile.open(IO_ReadOnly); 387 ret = qfile.open(IO_ReadOnly);
377 } 388 }
378 if ( ret ) { 389 if ( ret ) {
379 QTextStream t( &qfile ); 390 QTextStream t( &qfile );
380 QString s, line; 391 QString s, line;
381 parser.file = file; 392 parser.file = filename;
382 parser.line_no = 0; 393 parser.line_no = 0;
383 while ( !t.eof() ) { 394 while ( !t.eof() ) {
384 parser.line_no++; 395 parser.line_no++;
385 line = t.readLine().stripWhiteSpace(); 396 line = t.readLine().stripWhiteSpace();
386 int prelen = line.length(); 397 int prelen = line.length();
387 line.replace(QRegExp("#.*$"), ""); // bye comments 398 {
399 int hash_mark = line.find('#');
400 if(hash_mark != -1) //bye comments
401 line = line.left(hash_mark);
402 }
388 if(!line.isEmpty() && line.right(1) == "\\") { 403 if(!line.isEmpty() && line.right(1) == "\\") {
389 line.truncate(line.length() - 1); 404 line.truncate(line.length() - 1);
390 s += line + " "; 405 s += line + " ";
391 } else if(!line.isEmpty() || (line.isEmpty() && !prelen)) { 406 } else if(!line.isEmpty() || (line.isEmpty() && !prelen)) {
392 if(s.isEmpty() && line.isEmpty()) 407 if(s.isEmpty() && line.isEmpty())
393 continue; 408 continue;
@@ -405,18 +420,27 @@ QMakeProject::read(QString file, QMap<QString, QStringList> &place)
405 } 420 }
406 parser = pi; 421 parser = pi;
407 return ret; 422 return ret;
408} 423}
409 424
410bool 425bool
411QMakeProject::read(QString project, QString) 426QMakeProject::read(const QString &project, const QString &, bool just_project)
412{ 427{
428 if(just_project) { //nothing more, nothing less
429 pfile = project;
430 if(pfile != "-" && !QFile::exists(pfile) && pfile.right(4) != ".pro")
431 pfile += ".pro";
432 return read(pfile, vars);
433 }
434
413 if(cfile.isEmpty()) { 435 if(cfile.isEmpty()) {
414 // hack to get the Option stuff in there 436 // hack to get the Option stuff in there
415 base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext; 437 base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext;
416 base_vars["QMAKE_EXT_H"] = Option::h_ext; 438 base_vars["QMAKE_EXT_H"] = Option::h_ext;
439 if(!Option::user_template_prefix.isEmpty())
440 base_vars["TEMPLATE_PREFIX"] = Option::user_template_prefix;
417 441
418 /* parse the cache */ 442 /* parse the cache */
419 if(Option::mkfile::do_cache) { 443 if(Option::mkfile::do_cache) {
420 if(Option::mkfile::cachefile.isEmpty()) { //find it as it has not been specified 444 if(Option::mkfile::cachefile.isEmpty()) { //find it as it has not been specified
421 QString dir = QDir::convertSeparators(Option::output_dir); 445 QString dir = QDir::convertSeparators(Option::output_dir);
422 while(!QFile::exists((Option::mkfile::cachefile = dir + 446 while(!QFile::exists((Option::mkfile::cachefile = dir +
@@ -438,41 +462,29 @@ QMakeProject::read(QString project, QString)
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 }
468
469 if(Option::mkfile::qmakespec.isEmpty()) { 480 if(Option::mkfile::qmakespec.isEmpty()) {
470 fprintf(stderr, "QMAKESPEC has not been set, so configuration cannot be deduced.\n"); 481 fprintf(stderr, "QMAKESPEC has not been set, so configuration cannot be deduced.\n");
471 return FALSE; 482 return FALSE;
472 } 483 }
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;
@@ -541,18 +553,20 @@ QMakeProject::read(QString project, QString)
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;
@@ -576,20 +590,19 @@ QMakeProject::read(QString project, QString)
576 } 590 }
577 } 591 }
578 return TRUE; 592 return TRUE;
579} 593}
580 594
581bool 595bool
582QMakeProject::isActiveConfig(const QString &x) 596QMakeProject::isActiveConfig(const QString &x, bool regex)
583{ 597{
584 if(x.isEmpty()) 598 if(x.isEmpty())
585 return TRUE; 599 return TRUE;
586 600
587 QRegExp re(x, FALSE, TRUE); 601 if((Option::target_mode == Option::TARG_MACX_MODE || Option::target_mode == Option::TARG_QNX6_MODE ||
588 if((Option::target_mode == Option::TARG_MACX_MODE || Option::target_mode == Option::TARG_QNX6_MODE || Option::target_mode == Option::TARG_UNIX_MODE) && 602 Option::target_mode == Option::TARG_UNIX_MODE) && x == "unix")
589 x == "unix")
590 return TRUE; 603 return TRUE;
591 else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx") 604 else if(Option::target_mode == Option::TARG_MACX_MODE && x == "macx")
592 return TRUE; 605 return TRUE;
593 else if(Option::target_mode == Option::TARG_QNX6_MODE && x == "qnx6") 606 else if(Option::target_mode == Option::TARG_QNX6_MODE && x == "qnx6")
594 return TRUE; 607 return TRUE;
595 else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9") 608 else if(Option::target_mode == Option::TARG_MAC9_MODE && x == "mac9")
@@ -598,65 +611,77 @@ QMakeProject::isActiveConfig(const QString &x)
598 x == "mac") 611 x == "mac")
599 return TRUE; 612 return TRUE;
600 else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32") 613 else if(Option::target_mode == Option::TARG_WIN_MODE && x == "win32")
601 return TRUE; 614 return TRUE;
602 615
603 616
617 QRegExp re(x, FALSE, TRUE);
604 QString spec = Option::mkfile::qmakespec.right(Option::mkfile::qmakespec.length() - 618 QString spec = Option::mkfile::qmakespec.right(Option::mkfile::qmakespec.length() -
605 (Option::mkfile::qmakespec.findRev(QDir::separator())+1)); 619 (Option::mkfile::qmakespec.findRev(QDir::separator())+1));
606 if(re.exactMatch(spec)) 620 if((regex && re.exactMatch(spec)) || (!regex && spec == x))
607 return TRUE; 621 return TRUE;
608#ifdef Q_OS_UNIX 622#ifdef Q_OS_UNIX
609 else if(spec == "default") { 623 else if(spec == "default") {
610 static char *buffer = NULL; 624 static char *buffer = NULL;
611 if(!buffer) 625 if(!buffer)
612 buffer = (char *)malloc(1024); 626 buffer = (char *)malloc(1024);
613 int l = readlink(Option::mkfile::qmakespec, buffer, 1024); 627 int l = readlink(Option::mkfile::qmakespec, buffer, 1024);
614 if(l != -1) { 628 if(l != -1) {
615 buffer[l] = '\0'; 629 buffer[l] = '\0';
616 QString r = buffer; 630 QString r = buffer;
617 if(r.findRev('/') != -1) 631 if(r.findRev('/') != -1)
618 r = r.mid(r.findRev('/') + 1); 632 r = r.mid(r.findRev('/') + 1);
619 if(re.exactMatch(r)) 633 if((regex && re.exactMatch(r)) || (!regex && r == x))
620 return TRUE; 634 return TRUE;
621 } 635 }
622 } 636 }
623#endif 637#endif
624 638
625 639
626 QStringList &configs = vars["CONFIG"]; 640 QStringList &configs = vars["CONFIG"];
627 for(QStringList::Iterator it = configs.begin(); it != configs.end(); ++it) { 641 for(QStringList::Iterator it = configs.begin(); it != configs.end(); ++it) {
642 if((regex && re.exactMatch((*it))) || (!regex && (*it) == x))
628 if(re.exactMatch((*it))) 643 if(re.exactMatch((*it)))
629 return TRUE; 644 return TRUE;
630 } 645 }
631 return FALSE; 646 return FALSE;
632} 647}
633 648
634bool 649bool
635QMakeProject::doProjectTest(QString func, const QString &params, QMap<QString, QStringList> &place) 650QMakeProject::doProjectTest(const QString& func, const QString &params, QMap<QString, QStringList> &place)
636{ 651{
637 QStringList args = split_arg_list(params); 652 QStringList args = split_arg_list(params);
638 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) { 653 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) {
639 QString tmp = (*arit).stripWhiteSpace(); 654 QString tmp = (*arit).stripWhiteSpace();
640 if((tmp[0] == '\'' || tmp[0] == '"') && tmp.right(1) == tmp.left(1)) 655 if((tmp[0] == '\'' || tmp[0] == '"') && tmp.right(1) == tmp.left(1))
641 tmp = tmp.mid(1, tmp.length() - 2); 656 tmp = tmp.mid(1, tmp.length() - 2);
642 } 657 }
643 return doProjectTest(func.stripWhiteSpace(), args, place); 658 return doProjectTest(func.stripWhiteSpace(), args, place);
644} 659}
645 660
646bool 661bool
647QMakeProject::doProjectTest(QString func, QStringList args, QMap<QString, QStringList> &place) 662QMakeProject::doProjectTest(const QString& func, QStringList args, QMap<QString, QStringList> &place)
648{ 663{
649 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) { 664 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) {
650 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space 665 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space
651 doVariableReplace((*arit), place); 666 doVariableReplace((*arit), place);
652 } 667 }
653 debug_msg(1, "Running project test: %s( %s )", func.latin1(), args.join("::").latin1()); 668 debug_msg(1, "Running project test: %s( %s )", func.latin1(), args.join("::").latin1());
654 669
655 if(func == "requires") { 670 if(func == "requires") {
656 return doProjectCheckReqs(args, place); 671 return doProjectCheckReqs(args, place);
672 } else if(func == "equals") {
673 if(args.count() != 2) {
674 fprintf(stderr, "%s:%d: equals(variable, value) requires two arguments.\n", parser.file.latin1(),
675 parser.line_no);
676 return FALSE;
677 }
678 QString value = args[1];
679 if((value.left(1) == "\"" || value.left(1) == "'") && value.right(1) == value.left(1))
680 value = value.mid(1, value.length()-2);
681 return vars[args[0]].join(" ") == value;
657 } else if(func == "exists") { 682 } else if(func == "exists") {
658 if(args.count() != 1) { 683 if(args.count() != 1) {
659 fprintf(stderr, "%s:%d: exists(file) requires one argument.\n", parser.file.latin1(), 684 fprintf(stderr, "%s:%d: exists(file) requires one argument.\n", parser.file.latin1(),
660 parser.line_no); 685 parser.line_no);
661 return FALSE; 686 return FALSE;
662 } 687 }
@@ -804,24 +829,32 @@ QMakeProject::doProjectTest(QString func, QStringList args, QMap<QString, QStrin
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);
@@ -854,13 +887,13 @@ QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringL
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) {
@@ -874,96 +907,151 @@ QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringL
874} 907}
875 908
876 909
877QString 910QString
878QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &place) 911QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &place)
879{ 912{
880 for(int x = 0, rep; x < 5; x++) { 913 for(int var_begin, var_last=0; (var_begin = str.find("$$", var_last)) != -1; var_last = var_begin) {
881 QRegExp reg_var; 914 if(var_begin >= int( str.length() + 2 ) ) {
882 reg_var.setMinimal(TRUE); 915 break;
883 if( x == 0 ) //function blocked out by {}'s 916 } else if(var_begin != 0 && str[var_begin-1] == '\\') {
884 reg_var = QRegExp("\\$\\$\\{([a-zA-Z0-9_]*)\\((\\(.|(.*)\\)*)\\)\\}"); 917 str.replace(var_begin-1, 1, "");
885 else if( x == 1 ) //variables blocked out by {}'s 918 var_begin += 1;
886 reg_var = QRegExp("\\$\\$\\{([a-zA-Z0-9_\\.-]*)\\}"); 919 continue;
887 else if(x == 2) //environment 920 }
888 reg_var = QRegExp("\\$\\$\\(([a-zA-Z0-9_\\.-]*)\\)"); 921
889 else if(x == 3) //function 922 int var_incr = var_begin + 2;
890 reg_var = QRegExp("\\$\\$([a-zA-Z0-9_]*)\\((\\(.|(.*)\\)*)\\)"); 923 bool in_braces = FALSE, as_env = FALSE;
891 else if(x == 4) //normal variable 924 if(str[var_incr] == '{') {
892 reg_var = QRegExp("\\$\\$([a-zA-Z0-9_\\.-]*)"); 925 in_braces = TRUE;
893 while((rep = reg_var.search(str)) != -1) { 926 var_incr++;
927 while(var_incr < int( str.length() ) &&
928 (str[var_incr] == ' ' || str[var_incr] == '\t' || str[var_incr] == '\n'))
929 var_incr++;
930 }
931 if(str[var_incr] == '(') {
932 as_env = TRUE;
933 var_incr++;
934 }
935 QString val, args;
936 while(var_incr < int( str.length() ) &&
937 (str[var_incr].isLetter() || str[var_incr].isNumber() || str[var_incr] == '.' || str[var_incr] == '_'))
938 val += str[var_incr++];
939 if(as_env) {
940 if(str[var_incr] != ')') {
941 var_incr++;
942 warn_msg(WarnParser, "%s:%d: Unterminated env-variable replacement '%s' (%s)",
943 parser.file.latin1(), parser.line_no,
944 str.mid(var_begin, QMAX(var_incr - var_begin, int(str.length()))).latin1(), str.latin1());
945 var_begin += var_incr;
946 continue;
947 }
948 var_incr++;
949 } else if(str[var_incr] == '(') { //args
950 for(int parens = 0; var_incr < int( str.length() ); var_incr++) {
951 if(str[var_incr] == '(') {
952 parens++;
953 if(parens == 1)
954 continue;
955 } else if(str[var_incr] == ')') {
956 parens--;
957 if(!parens) {
958 var_incr++;
959 break;
960 }
961 }
962 args += str[var_incr];
963 }
964 }
965 if(var_incr > int( str.length() ) || (in_braces && str[var_incr] != '}')) {
966 var_incr++;
967 warn_msg(WarnParser, "%s:%d: Unterminated variable replacement '%s' (%s)",
968 parser.file.latin1(), parser.line_no,
969 str.mid(var_begin, QMAX(var_incr - var_begin, int( str.length() ))).latin1(), str.latin1());
970 var_begin += var_incr;
971 continue;
972 } else if(in_braces) {
973 var_incr++;
974 }
975
894 QString replacement; 976 QString replacement;
895 if(x == 2) {//environment 977 if(as_env) {
896 replacement = getenv(reg_var.cap(1)); 978 replacement = getenv(val);
897 } else if(x == 0 || x == 3) { //function 979 } else if(args.isEmpty()) {
898 QStringList args = split_arg_list(reg_var.cap(2)); 980 if(val.left(1) == ".")
899 for(QStringList::Iterator arit = args.begin(); arit != args.end(); ++arit) { 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) {
900 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space 989 (*arit) = (*arit).stripWhiteSpace(); // blah, get rid of space
901 doVariableReplace((*arit), place); 990 doVariableReplace((*arit), place);
902 } 991 }
903 debug_msg(1, "Running function: %s( %s )", reg_var.cap(1).latin1(), args.join("::").latin1()); 992 debug_msg(1, "Running function: %s( %s )", val.latin1(), arg_list.join("::").latin1());
904 if(reg_var.cap(1).lower() == "member") { 993 if(val.lower() == "member") {
905 if(args.count() < 1 || args.count() > 2) { 994 if(arg_list.count() < 1 || arg_list.count() > 2) {
906 fprintf(stderr, "%s:%d: member(var, place) requires two arguments.\n", 995 fprintf(stderr, "%s:%d: member(var, place) requires two arguments.\n",
907 parser.file.latin1(), parser.line_no); 996 parser.file.latin1(), parser.line_no);
908 } else { 997 } else {
909 uint pos = 0; 998 uint pos = 0;
910 if(args.count() == 2) 999 if(arg_list.count() == 2)
911 pos = args[1].toInt(); 1000 pos = arg_list[1].toInt();
912 const QStringList &var = place[varMap(args.first())]; 1001 const QStringList &var = place[varMap(arg_list.first())];
913 if(var.count() >= pos) 1002 if(var.count() >= pos)
914 replacement = var[pos]; 1003 replacement = var[pos];
915 } 1004 }
916 } else if(reg_var.cap(1).lower() == "list") { 1005 } else if(val.lower() == "list") {
917 if(args.count() != 1) {
918 fprintf(stderr, "%s:%d: list(vals) requires one"
919 "argument.\n", parser.file.latin1(), parser.line_no);
920 } else {
921 static int x = 0; 1006 static int x = 0;
922 replacement.sprintf(".QMAKE_INTERNAL_TMP_VAR_%d", x++); 1007 replacement.sprintf(".QMAKE_INTERNAL_TMP_VAR_%d", x++);
923 (*((QMap<QString, QStringList>*)&place))[replacement] = split_value_list(args.first()); 1008 QStringList &lst = (*((QMap<QString, QStringList>*)&place))[replacement];
924 } 1009 lst.clear();
925 } else if(reg_var.cap(1).lower() == "join") { 1010 for(QStringList::ConstIterator arg_it = arg_list.begin();
926 if(args.count() < 1 || args.count() > 4) { 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) {
927 fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four" 1015 fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four"
928 "arguments.\n", parser.file.latin1(), parser.line_no); 1016 "arguments.\n", parser.file.latin1(), parser.line_no);
929 } else { 1017 } else {
930 QString glue, before, after; 1018 QString glue, before, after;
931 if(args.count() >= 2) 1019 if(arg_list.count() >= 2)
932 glue = args[1].replace("\"", "" ); 1020 glue = arg_list[1].replace("\"", "" );
933 if(args.count() >= 3) 1021 if(arg_list.count() >= 3)
934 before = args[2].replace("\"", "" ); 1022 before = arg_list[2].replace("\"", "" );
935 if(args.count() == 4) 1023 if(arg_list.count() == 4)
936 after = args[3].replace("\"", "" ); 1024 after = arg_list[3].replace("\"", "" );
937 const QStringList &var = place[varMap(args.first())]; 1025 const QStringList &var = place[varMap(arg_list.first())];
938 if(!var.isEmpty()) 1026 if(!var.isEmpty())
939 replacement = before + var.join(glue) + after; 1027 replacement = before + var.join(glue) + after;
940 } 1028 }
941 } else if(reg_var.cap(1).lower() == "find") { 1029 } else if(val.lower() == "find") {
942 if(args.count() != 2) { 1030 if(arg_list.count() != 2) {
943 fprintf(stderr, "%s:%d find(var, str) requires two arguments\n", 1031 fprintf(stderr, "%s:%d find(var, str) requires two arguments\n",
944 parser.file.latin1(), parser.line_no); 1032 parser.file.latin1(), parser.line_no);
945 } else { 1033 } else {
946 QRegExp regx(args[1]); 1034 QRegExp regx(arg_list[1]);
947 const QStringList &var = place[varMap(args.first())]; 1035 const QStringList &var = place[varMap(arg_list.first())];
948 for(QStringList::ConstIterator vit = var.begin(); 1036 for(QStringList::ConstIterator vit = var.begin();
949 vit != var.end(); ++vit) { 1037 vit != var.end(); ++vit) {
950 if(regx.search(*vit) != -1) { 1038 if(regx.search(*vit) != -1) {
951 if(!replacement.isEmpty()) 1039 if(!replacement.isEmpty())
952 replacement += " "; 1040 replacement += " ";
953 replacement += (*vit); 1041 replacement += (*vit);
954 } 1042 }
955 } 1043 }
956 } 1044 }
957 } else if(reg_var.cap(1).lower() == "system") { 1045 } else if(val.lower() == "system") {
958 if(args.count() != 1) { 1046 if(arg_list.count() != 1) {
959 fprintf(stderr, "%s:%d system(execut) requires one argument\n", 1047 fprintf(stderr, "%s:%d system(execut) requires one argument\n",
960 parser.file.latin1(), parser.line_no); 1048 parser.file.latin1(), parser.line_no);
961 } else { 1049 } else {
962 char buff[256]; 1050 char buff[256];
963 FILE *proc = QT_POPEN(args.join(" ").latin1(), "r"); 1051 FILE *proc = QT_POPEN(arg_list.join(" ").latin1(), "r");
964 while(proc && !feof(proc)) { 1052 while(proc && !feof(proc)) {
965 int read_in = fread(buff, 1, 255, proc); 1053 int read_in = fread(buff, 1, 255, proc);
966 if(!read_in) 1054 if(!read_in)
967 break; 1055 break;
968 for(int i = 0; i < read_in; i++) { 1056 for(int i = 0; i < read_in; i++) {
969 if(buff[i] == '\n' || buff[i] == '\t') 1057 if(buff[i] == '\n' || buff[i] == '\t')
@@ -972,23 +1060,18 @@ QMakeProject::doVariableReplace(QString &str, const QMap<QString, QStringList> &
972 buff[read_in] = '\0'; 1060 buff[read_in] = '\0';
973 replacement += buff; 1061 replacement += buff;
974 } 1062 }
975 } 1063 }
976 } else { 1064 } else {
977 fprintf(stderr, "%s:%d: Unknown replace function: %s\n", 1065 fprintf(stderr, "%s:%d: Unknown replace function: %s\n",
978 parser.file.latin1(), parser.line_no, reg_var.cap(1).latin1()); 1066 parser.file.latin1(), parser.line_no, val.latin1());
979 }
980 } else { //variable
981 if(reg_var.cap(1).left(1) == ".")
982 replacement = "";
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}