Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

project.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** 
00003 **
00004 ** Implementation of QMakeProject class.
00005 **
00006 ** Copyright (C) 1992-2003 Trolltech AS.  All rights reserved.
00007 **
00008 ** This file is part of qmake.
00009 **
00010 ** This file may be distributed under the terms of the Q Public License
00011 ** as defined by Trolltech AS of Norway and appearing in the file
00012 ** LICENSE.QPL included in the packaging of this file.
00013 **
00014 ** This file may be distributed and/or modified under the terms of the
00015 ** GNU General Public License version 2 as published by the Free Software
00016 ** Foundation and appearing in the file LICENSE.GPL included in the
00017 ** packaging of this file.
00018 **
00019 ** Licensees holding valid Qt Enterprise Edition licenses may use this
00020 ** file in accordance with the Qt Commercial License Agreement provided
00021 ** with the Software.
00022 **
00023 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00024 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00025 **
00026 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
00027 **   information about Qt Commercial License Agreements.
00028 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
00029 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00030 **
00031 ** Contact info@trolltech.com if any conditions of this licensing are
00032 ** not clear to you.
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     /* prefer $QTDIR if it is set */
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")) //tmake no more!
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 &params)
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++]; //get that 'escape'
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     /* scope blocks start at true */
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) //good bye comments
00210         s = s.left(hash_mark);
00211     if(s.isEmpty()) /* blank_line */
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         /* adjust scope for each block which appears on a single line */
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; /* need this */
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) { /* if there is an lparen in the scope, it IS a function */
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;  /* assume we are done */
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 == '{') { /* scoping block */
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; /* oh well */
00346     if(!*d) {
00347         if(!var.stripWhiteSpace().isEmpty())
00348             qmake_error_msg("Parse Error ('" + s + "')");
00349         return var.isEmpty(); /* allow just a scope */
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); /* vals now contains the space separated list of values */
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); //backwards compatability
00383 
00384     /* vallist is the broken up list of values */
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]; /* varlist is the list in the symbol table */
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     /* now do the operation */
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") /* special case to get communicated to backends! */
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) //good bye comments
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         // hack to get the Option stuff in there
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) {       /* parse the cache */
00528             if(Option::mkfile::cachefile.isEmpty())  { //find it as it has not been specified
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) {        /* parse mkspec */
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             /* parse qmake configuration */
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             /* commandline */
00601             cfile = pfile;
00602             parser.line_no = 1; //really arg count now.. duh
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; /* start with the base */
00617 
00618     if(cmd & ReadProFile) { /* parse project file */
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) { /* parse post files */
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; //really arg count now.. duh
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     /* now let the user override the template from an option.. */
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         // ### why not simply use:
00664         // QFileInfo fi(pfile);
00665         // fi.baseName();
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 //          fprintf(stderr,"Current QT version number: " + ver + "\n");
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 &params, 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(); // blah, get rid of space
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         //regular expression I guess
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) //nice to see this first..
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) { /* if there is an lparen in the chk, it IS a function */
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] == '(') { //args
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         //actually do replacement now..
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 }

Generated on Sat Nov 5 16:18:28 2005 for OPIE by  doxygen 1.4.2