diff --git a/shared/proparser/profileevaluator.cpp b/shared/proparser/profileevaluator.cpp index 9545ac4eb9f7177d1f9391ca88a09408a6e808da..ba7a31d6e06254a1078cfef11d9dd044e8a3d331 100644 --- a/shared/proparser/profileevaluator.cpp +++ b/shared/proparser/profileevaluator.cpp @@ -131,6 +131,12 @@ class ProFileEvaluator::Private : public AbstractProItemVisitor public: Private(ProFileEvaluator *q_); + ProFileEvaluator *q; + int m_lineNo; // Error reporting + bool m_verbose; + + /////////////// Reading pro file + bool read(ProFile *pro); ProBlock *currentBlock(); @@ -143,6 +149,17 @@ public: void leaveScope(); void finalizeBlock(); + QStack<ProBlock *> m_blockstack; + ProBlock *m_block; + + ProItem *m_commentItem; + QString m_proitem; + QString m_pendingComment; + bool m_syntaxError; + bool m_contNextLine; + + /////////////// Evaluating pro file contents + // implementation of AbstractProItemVisitor bool visitBeginProBlock(ProBlock *block); bool visitEndProBlock(ProBlock *block); @@ -180,21 +197,16 @@ public: QStringList qmakeFeaturePaths(); - ProFileEvaluator *q; - - QStack<ProBlock *> m_blockstack; - ProBlock *m_block; - - ProItem *m_commentItem; - QString m_proitem; - QString m_pendingComment; - bool m_syntaxError; - bool m_contNextLine; - bool m_condition; + enum { ConditionTrue, ConditionFalse, ConditionElse }; + int m_condition; + int m_prevCondition; + bool m_updateCondition; bool m_invertNext; + int m_skipLevel; + bool m_cumulative; QString m_lastVarName; ProVariable::VariableOperator m_variableOperator; - int m_lineNo; // Error reporting + QString m_origfile; QString m_oldPath; // To restore the current path to the path QStack<ProFile*> m_profileStack; // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri' @@ -202,12 +214,9 @@ public: QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file QHash<QString, QString> m_properties; QString m_outputDir; - QString m_origfile; int m_prevLineNo; // Checking whether we're assigning the same TARGET ProFile *m_prevProFile; // See m_prevLineNo - - bool m_verbose; }; ProFileEvaluator::Private::Private(ProFileEvaluator *q_) @@ -221,6 +230,11 @@ ProFileEvaluator::Private::Private(ProFileEvaluator *q_) m_syntaxError = 0; m_lineNo = 0; m_contNextLine = false; + m_cumulative = true; + m_updateCondition = false; + m_condition = ConditionFalse; + m_invertNext = false; + m_skipLevel = 0; } bool ProFileEvaluator::Private::read(ProFile *pro) @@ -512,15 +526,25 @@ void ProFileEvaluator::Private::updateItem() bool ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block) { if (block->blockKind() == ProBlock::ScopeKind) { - m_invertNext = false; - m_condition = false; + m_updateCondition = true; + if (!m_skipLevel) { + m_prevCondition = m_condition; + m_condition = ConditionFalse; + } + } else if (block->blockKind() & ProBlock::ScopeContentsKind) { + m_updateCondition = false; + if (m_condition != ConditionTrue) + ++m_skipLevel; } return true; } bool ProFileEvaluator::Private::visitEndProBlock(ProBlock *block) { - Q_UNUSED(block); + if (block->blockKind() & ProBlock::ScopeContentsKind) { + if (m_skipLevel) + --m_skipLevel; + } return true; } @@ -546,12 +570,16 @@ bool ProFileEvaluator::Private::visitProOperator(ProOperator *oper) bool ProFileEvaluator::Private::visitProCondition(ProCondition *cond) { - if (!m_condition) { - if (m_invertNext) - m_condition |= !isActiveConfig(cond->text(), true); - else - m_condition |= isActiveConfig(cond->text(), true); + if (!m_skipLevel) { + if (cond->text().toLower() == QLatin1String("else")) { + if (m_prevCondition == ConditionTrue) + m_condition = ConditionElse; + } else if (m_condition == ConditionFalse) { + if (isActiveConfig(cond->text(), true) ^ m_invertNext) + m_condition = ConditionTrue; + } } + m_invertNext = false; return true; } @@ -574,10 +602,13 @@ bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro) const QString mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS")); if (!mkspecDirectory.isEmpty()) { + bool cumulative = m_cumulative; + m_cumulative = false; // This is what qmake does, everything set in the mkspec is also set // But this also creates a lot of problems evaluateFile(mkspecDirectory + QLatin1String("/default/qmake.conf"), &ok); evaluateFile(mkspecDirectory + QLatin1String("/features/default_pre.prf"), &ok); + m_cumulative = cumulative; } QString fn = pro->fileName(); @@ -595,6 +626,9 @@ bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro) if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) { const QString &mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS")); if (!mkspecDirectory.isEmpty()) { + bool cumulative = m_cumulative; + m_cumulative = false; + evaluateFile(mkspecDirectory + QLatin1String("/features/default_post.prf"), &ok); QSet<QString> processed; @@ -616,6 +650,8 @@ bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro) if (finished) break; } + + m_cumulative = cumulative; } m_profileStack.pop(); @@ -624,6 +660,24 @@ bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro) return ok; } +static void replaceInList(QStringList *varlist, + const QRegExp ®exp, const QString &replace, bool global) +{ + for (QStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) { + if ((*varit).contains(regexp)) { + (*varit).replace(regexp, replace); + if ((*varit).isEmpty()) + varit = varlist->erase(varit); + else + ++varit; + if(!global) + break; + } else { + ++varit; + } + } +} + bool ProFileEvaluator::Private::visitProValue(ProValue *value) { PRE(value); @@ -675,37 +729,53 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) } switch (m_variableOperator) { - case ProVariable::UniqueAddOperator: // * - insertUnique(&m_valuemap, varName, v, true); - insertUnique(&m_filevaluemap[currentProFile()], varName, v, true); - break; case ProVariable::SetOperator: // = - case ProVariable::AddOperator: // + - insertUnique(&m_valuemap, varName, v, false); - insertUnique(&m_filevaluemap[currentProFile()], varName, v, false); + if (!m_cumulative) { + if (!m_skipLevel) { + m_valuemap[varName] = v; + m_filevaluemap[currentProFile()][varName] = v; + } + } else { + // We are greedy for values. + m_valuemap[varName] += v; + m_filevaluemap[currentProFile()][varName] += v; + } break; - case ProVariable::RemoveOperator: // - - // fix me: interaction between AddOperator and RemoveOperator - insertUnique(&m_valuemap, varName.prepend(QLatin1Char('-')), v, false); - insertUnique(&m_filevaluemap[currentProFile()], - varName.prepend(QLatin1Char('-')), v, false); + case ProVariable::UniqueAddOperator: // *= + if (!m_skipLevel || m_cumulative) { + insertUnique(&m_valuemap, varName, v); + insertUnique(&m_filevaluemap[currentProFile()], varName, v); + } break; - case ProVariable::ReplaceOperator: // ~ + case ProVariable::AddOperator: // += + if (!m_skipLevel || m_cumulative) { + m_valuemap[varName] += v; + m_filevaluemap[currentProFile()][varName] += v; + } + break; + case ProVariable::RemoveOperator: // -= + if (!m_cumulative) { + if (!m_skipLevel) { + removeEach(&m_valuemap, varName, v); + removeEach(&m_filevaluemap[currentProFile()], varName, v); + } + } else { + // We are stingy with our values, too. + } + break; + case ProVariable::ReplaceOperator: // ~= { // DEFINES ~= s/a/b/?[gqi] -/* Create a superset by executing replacement + adding items that have changed - to original list. We're not sure if this is really the right approach, so for - the time being we will just do nothing ... - + // FIXME: qmake variable-expands val first. + if (val.length() < 4 || val[0] != QLatin1Char('s')) { + q->logMessage(format("the ~= operator can handle only the s/// function.")); + return false; + } QChar sep = val.at(1); QStringList func = val.split(sep); if (func.count() < 3 || func.count() > 4) { - q->logMessage(format("'~= operator '(function s///) expects 3 or 4 arguments.")); - return false; - } - if (func[0] != QLatin1String("s")) { - q->logMessage(format("~= operator can only handle s/// function.")); + q->logMessage(format("the s/// function expects 3 or 4 arguments.")); return false; } @@ -722,19 +792,12 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive); - QStringList replaceList = replaceInList(m_valuemap.value(varName), regexp, replace, - global); - // Add changed entries to list - foreach (const QString &entry, replaceList) - if (!m_valuemap.value(varName).contains(entry)) - insertUnique(&m_valuemap, varName, QStringList() << entry, false); - - replaceList = replaceInList(m_filevaluemap[currentProFile()].value(varName), regexp, - replace, global); - foreach (const QString &entry, replaceList) - if (!m_filevaluemap[currentProFile()].value(varName).contains(entry)) - insertUnique(&m_filevaluemap[currentProFile()], varName, - QStringList() << entry, false); */ + if (!m_skipLevel || m_cumulative) { + // We could make a union of modified and unmodified values, + // but this will break just as much as it fixes, so leave it as is. + replaceInList(&m_valuemap[varName], regexp, replace, global); + replaceInList(&m_filevaluemap[currentProFile()][varName], regexp, replace, global); + } } break; @@ -744,18 +807,22 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) bool ProFileEvaluator::Private::visitProFunction(ProFunction *func) { - m_lineNo = func->lineNumber(); - bool result = true; - bool ok = true; - QString text = func->text(); - int lparen = text.indexOf(QLatin1Char('(')); - int rparen = text.lastIndexOf(QLatin1Char(')')); - QTC_ASSERT(lparen < rparen, return false); - - QString arguments = text.mid(lparen + 1, rparen - lparen - 1); - QString funcName = text.left(lparen); - ok &= evaluateConditionalFunction(funcName.trimmed(), arguments, &result); - return ok; + if (!m_skipLevel && (!m_updateCondition || m_condition == ConditionFalse)) { + QString text = func->text(); + int lparen = text.indexOf(QLatin1Char('(')); + int rparen = text.lastIndexOf(QLatin1Char(')')); + QTC_ASSERT(lparen < rparen, return false); + QString arguments = text.mid(lparen + 1, rparen - lparen - 1); + QString funcName = text.left(lparen); + m_lineNo = func->lineNumber(); + bool result = false; + if (!evaluateConditionalFunction(funcName.trimmed(), arguments, &result)) + return false; + if (result ^ m_invertNext) + m_condition = ConditionTrue; + } + m_invertNext = false; + return true; } @@ -2083,18 +2150,20 @@ void ProFileEvaluator::addProperties(const QHash<QString, QString> &properties) void ProFileEvaluator::logMessage(const QString &message) { - if (d->m_verbose) + if (d->m_verbose && !d->m_skipLevel) qWarning("%s", qPrintable(message)); } void ProFileEvaluator::fileMessage(const QString &message) { - qWarning("%s", qPrintable(message)); + if (!d->m_skipLevel) + qWarning("%s", qPrintable(message)); } void ProFileEvaluator::errorMessage(const QString &message) { - qWarning("%s", qPrintable(message)); + if (!d->m_skipLevel) + qWarning("%s", qPrintable(message)); } // This function is unneeded and still retained. See log message for reason. @@ -2116,6 +2185,11 @@ void ProFileEvaluator::setVerbose(bool on) d->m_verbose = on; } +void ProFileEvaluator::setCumulative(bool on) +{ + d->m_cumulative = on; +} + void ProFileEvaluator::setOutputDir(const QString &dir) { d->m_outputDir = dir; diff --git a/shared/proparser/profileevaluator.h b/shared/proparser/profileevaluator.h index 15854708c61a582ff5a59d121d675cc0f880b7df..83ba9361eb87454bc5ff835c99c84d0d7cc3ab5b 100644 --- a/shared/proparser/profileevaluator.h +++ b/shared/proparser/profileevaluator.h @@ -69,6 +69,7 @@ public: QStringList absFileNames(const QString &variableName); QStringList absFileName(const QString &name); void setVerbose(bool on); // Default is false + void setCumulative(bool on); // Default is true! void setOutputDir(const QString &dir); // Default is empty bool queryProFile(ProFile *pro); diff --git a/shared/proparser/proparserutils.h b/shared/proparser/proparserutils.h index fbff5eb3e2c1a6739cd5cd756e36f71872482610..4c457eebd52fa3e23e6d90d22072909e6bffd0cb 100644 --- a/shared/proparser/proparserutils.h +++ b/shared/proparser/proparserutils.h @@ -132,17 +132,20 @@ static void unquote(QString *string) } static void insertUnique(QHash<QString, QStringList> *map, - const QString &key, const QStringList &value, bool unique = true) + const QString &key, const QStringList &value) { QStringList &sl = (*map)[key]; - if (!unique) { - sl += value; - } else { - for (int i = 0; i < value.count(); ++i) { - if (!sl.contains(value.at(i))) - sl.append(value.at(i)); - } - } + foreach (const QString &str, value) + if (!sl.contains(str)) + sl.append(str); +} + +static void removeEach(QHash<QString, QStringList> *map, + const QString &key, const QStringList &value) +{ + QStringList &sl = (*map)[key]; + foreach (const QString &str, value) + sl.removeAll(str); } /*