Source

Target

Commits (17)
Showing with 187 additions and 102 deletions
...@@ -52,10 +52,12 @@ ...@@ -52,10 +52,12 @@
#include <QtGui/QKeyEvent> #include <QtGui/QKeyEvent>
#include <QtWidgets/QMenu> #include <QtWidgets/QMenu>
#ifndef QT_NO_PRINTER
#include <QtPrintSupport/QPageSetupDialog> #include <QtPrintSupport/QPageSetupDialog>
#include <QtPrintSupport/QPrintDialog> #include <QtPrintSupport/QPrintDialog>
#include <QtPrintSupport/QPrintPreviewDialog> #include <QtPrintSupport/QPrintPreviewDialog>
#include <QtPrintSupport/QPrinter> #include <QtPrintSupport/QPrinter>
#endif
#include <QtWidgets/QStackedWidget> #include <QtWidgets/QStackedWidget>
#include <QtWidgets/QTextBrowser> #include <QtWidgets/QTextBrowser>
#include <QtWidgets/QVBoxLayout> #include <QtWidgets/QVBoxLayout>
......
...@@ -403,7 +403,15 @@ void MainWindow::lookForNewQtDocumentation() ...@@ -403,7 +403,15 @@ void MainWindow::lookForNewQtDocumentation()
<< QLatin1String("qtwebkitexamples") << QLatin1String("qtwebkitexamples")
<< QLatin1String("qtwidgets") << QLatin1String("qtwidgets")
<< QLatin1String("qtxml") << QLatin1String("qtxml")
<< QLatin1String("qtxmlpatterns"); << QLatin1String("qtxmlpatterns")
<< QLatin1String("qdoc")
<< QLatin1String("qtsensors")
<< QLatin1String("qtx11extras")
<< QLatin1String("qtserialport")
<< QLatin1String("qtscripttools")
<< QLatin1String("qtquickcontrols")
<< QLatin1String("qtquicklayouts")
<< QLatin1String("qtmultimediawidgets");
QList<QtDocInstaller::DocInfo> qtDocInfos; QList<QtDocInstaller::DocInfo> qtDocInfos;
foreach (const QString &doc, docs) foreach (const QString &doc, docs)
......
...@@ -85,7 +85,9 @@ ...@@ -85,7 +85,9 @@
#include <QtGui/QImage> #include <QtGui/QImage>
#include <QtGui/QPixmap> #include <QtGui/QPixmap>
#include <QtWidgets/QMdiSubWindow> #include <QtWidgets/QMdiSubWindow>
#ifndef QT_NO_PRINTER
#include <QtPrintSupport/QPrintDialog> #include <QtPrintSupport/QPrintDialog>
#endif
#include <QtGui/QPainter> #include <QtGui/QPainter>
#include <QtGui/QTransform> #include <QtGui/QTransform>
#include <QtGui/QCursor> #include <QtGui/QCursor>
...@@ -1044,7 +1046,7 @@ QAction *QDesignerActions::minimizeAction() const ...@@ -1044,7 +1046,7 @@ QAction *QDesignerActions::minimizeAction() const
void QDesignerActions::showDesignerHelp() void QDesignerActions::showDesignerHelp()
{ {
QString url = AssistantClient::designerManualUrl(); QString url = AssistantClient::designerManualUrl();
url += QStringLiteral("qtdesigner-index.html"); url += QStringLiteral("qtdesigner-manual.html");
showHelp(url); showHelp(url);
} }
......
...@@ -47,7 +47,9 @@ ...@@ -47,7 +47,9 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QPointer> #include <QtCore/QPointer>
#ifndef QT_NO_PRINTER
#include <QtPrintSupport/QPrinter> #include <QtPrintSupport/QPrinter>
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
......
...@@ -365,7 +365,6 @@ void WidgetDataBase::loadPlugins() ...@@ -365,7 +365,6 @@ void WidgetDataBase::loadPlugins()
{ {
typedef QMap<QString, int> NameIndexMap; typedef QMap<QString, int> NameIndexMap;
typedef QList<QDesignerWidgetDataBaseItemInterface*> ItemList; typedef QList<QDesignerWidgetDataBaseItemInterface*> ItemList;
typedef QMap<QString, QDesignerWidgetDataBaseItemInterface*> NameItemMap;
typedef QSet<QString> NameSet; typedef QSet<QString> NameSet;
// 1) create a map of existing custom classes // 1) create a map of existing custom classes
NameIndexMap existingCustomClasses; NameIndexMap existingCustomClasses;
......
...@@ -215,12 +215,16 @@ const QMetaObject *QDesignerAxPluginWidget::metaObject() const ...@@ -215,12 +215,16 @@ const QMetaObject *QDesignerAxPluginWidget::metaObject() const
return QDesignerAxWidget::metaObject(); return QDesignerAxWidget::metaObject();
} }
#ifndef QT_NO_EXCEPTIONS
static QString msgComException(const QObject *o, const QMetaObject::Call call, int index) static QString msgComException(const QObject *o, const QMetaObject::Call call, int index)
{ {
return QDesignerAxWidget::tr("A COM exception occurred when executing a meta call of type %1, index %2 of \"%3\"."). return QDesignerAxWidget::tr("A COM exception occurred when executing a meta call of type %1, index %2 of \"%3\".").
arg(call).arg(index).arg(o->objectName()); arg(call).arg(index).arg(o->objectName());
} }
#endif // QT_NO_EXCEPTIONS
int QDesignerAxPluginWidget::qt_metacall(QMetaObject::Call call, int signal, void **argv) int QDesignerAxPluginWidget::qt_metacall(QMetaObject::Call call, int signal, void **argv)
{ {
QAxWidget *aw = axobject(); QAxWidget *aw = axobject();
......
...@@ -307,6 +307,9 @@ enum ProToken { ...@@ -307,6 +307,9 @@ enum ProToken {
TokTestCall, // previous literal/expansion is a test function call TokTestCall, // previous literal/expansion is a test function call
// - ((nested expansion + TokArgSeparator)* + nested expansion)? // - ((nested expansion + TokArgSeparator)* + nested expansion)?
// - TokFuncTerminator // - TokFuncTerminator
TokReturn, // previous literal/expansion is a return value
TokBreak, // break loop
TokNext, // shortcut to next loop iteration
TokNot, // '!' operator TokNot, // '!' operator
TokAnd, // ':' operator TokAnd, // ':' operator
TokOr, // '|' operator TokOr, // '|' operator
......
...@@ -96,7 +96,7 @@ enum ExpandFunc { ...@@ -96,7 +96,7 @@ enum ExpandFunc {
enum TestFunc { enum TestFunc {
T_INVALID = 0, T_REQUIRES, T_GREATERTHAN, T_LESSTHAN, T_EQUALS, T_INVALID = 0, T_REQUIRES, T_GREATERTHAN, T_LESSTHAN, T_EQUALS,
T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM, T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM,
T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE, T_DEFINED, T_CONTAINS, T_INFILE,
T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_LOG, T_MESSAGE, T_WARNING, T_ERROR, T_IF, T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_LOG, T_MESSAGE, T_WARNING, T_ERROR, T_IF,
T_MKPATH, T_WRITE_FILE, T_TOUCH, T_CACHE T_MKPATH, T_WRITE_FILE, T_TOUCH, T_CACHE
}; };
...@@ -168,9 +168,6 @@ void QMakeEvaluator::initFunctionStatics() ...@@ -168,9 +168,6 @@ void QMakeEvaluator::initFunctionStatics()
{ "if", T_IF }, { "if", T_IF },
{ "isActiveConfig", T_CONFIG }, { "isActiveConfig", T_CONFIG },
{ "system", T_SYSTEM }, { "system", T_SYSTEM },
{ "return", T_RETURN },
{ "break", T_BREAK },
{ "next", T_NEXT },
{ "defined", T_DEFINED }, { "defined", T_DEFINED },
{ "contains", T_CONTAINS }, { "contains", T_CONTAINS },
{ "infile", T_INFILE }, { "infile", T_INFILE },
...@@ -470,8 +467,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( ...@@ -470,8 +467,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
QString tmp = args.at(0).toQString(m_tmp1); QString tmp = args.at(0).toQString(m_tmp1);
for (int i = 1; i < args.count(); ++i) for (int i = 1; i < args.count(); ++i)
tmp = tmp.arg(args.at(i).toQString(m_tmp2)); tmp = tmp.arg(args.at(i).toQString(m_tmp2));
// Note: this depends on split_value_list() making a deep copy ret << ProString(tmp);
ret = split_value_list(tmp);
} }
break; break;
case E_FORMAT_NUMBER: case E_FORMAT_NUMBER:
...@@ -564,7 +560,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( ...@@ -564,7 +560,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
src = s; src = s;
break; break;
} }
ret = split_value_list(before + var.join(glue) + after, src); ret << ProString(before + var.join(glue) + after).setSource(src);
} }
} }
break; break;
...@@ -1071,17 +1067,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1071,17 +1067,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return returnBool(m_functionDefs.replaceFunctions.contains(var) return returnBool(m_functionDefs.replaceFunctions.contains(var)
|| m_functionDefs.testFunctions.contains(var)); || m_functionDefs.testFunctions.contains(var));
} }
case T_RETURN:
m_returnValue = args;
// It is "safe" to ignore returns - due to qmake brokeness
// they cannot be used to terminate loops anyway.
if (m_cumulative)
return ReturnTrue;
if (m_valuemapStack.size() == 1) {
evalError(fL1S("unexpected return()."));
return ReturnFalse;
}
return ReturnReturn;
case T_EXPORT: { case T_EXPORT: {
if (args.count() != 1) { if (args.count() != 1) {
evalError(fL1S("export(variable) requires one argument.")); evalError(fL1S("export(variable) requires one argument."));
...@@ -1132,11 +1117,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1132,11 +1117,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
} }
} }
return ReturnFalse; return ReturnFalse;
#ifdef PROEVALUATOR_FULL
case T_REQUIRES: case T_REQUIRES:
#ifdef PROEVALUATOR_FULL
checkRequirements(args); checkRequirements(args);
return ReturnFalse; // Another qmake breakage
#endif #endif
return ReturnFalse; // Another qmake breakage
case T_EVAL: { case T_EVAL: {
VisitReturn ret = ReturnFalse; VisitReturn ret = ReturnFalse;
ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep), ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep),
...@@ -1152,20 +1137,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1152,20 +1137,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
} }
return ret; return ret;
} }
case T_BREAK:
if (m_skipLevel)
return ReturnFalse;
if (m_loopLevel)
return ReturnBreak;
evalError(fL1S("Unexpected break()."));
return ReturnFalse;
case T_NEXT:
if (m_skipLevel)
return ReturnFalse;
if (m_loopLevel)
return ReturnNext;
evalError(fL1S("Unexpected next()."));
return ReturnFalse;
case T_IF: { case T_IF: {
if (args.count() != 1) { if (args.count() != 1) {
evalError(fL1S("if(condition) requires one argument.")); evalError(fL1S("if(condition) requires one argument."));
...@@ -1412,14 +1383,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1412,14 +1383,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
} }
return (func_t == T_ERROR && !m_cumulative) ? ReturnError : ReturnTrue; return (func_t == T_ERROR && !m_cumulative) ? ReturnError : ReturnTrue;
} }
#ifdef PROEVALUATOR_FULL
case T_SYSTEM: { case T_SYSTEM: {
if (m_cumulative) // Anything else would be insanity
return ReturnFalse;
if (args.count() != 1) { if (args.count() != 1) {
evalError(fL1S("system(exec) requires one argument.")); evalError(fL1S("system(exec) requires one argument."));
return ReturnFalse; return ReturnFalse;
} }
#ifdef PROEVALUATOR_FULL
if (m_cumulative) // Anything else would be insanity
return ReturnFalse;
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
QProcess proc; QProcess proc;
proc.setProcessChannelMode(QProcess::ForwardedChannels); proc.setProcessChannelMode(QProcess::ForwardedChannels);
...@@ -1430,8 +1401,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1430,8 +1401,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
+ IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory())) + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory()))
+ QLatin1String(" && ") + args.at(0)).toLocal8Bit().constData()) == 0); + QLatin1String(" && ") + args.at(0)).toLocal8Bit().constData()) == 0);
#endif #endif
} #else
return ReturnTrue;
#endif #endif
}
case T_ISEMPTY: { case T_ISEMPTY: {
if (args.count() != 1) { if (args.count() != 1) {
evalError(fL1S("isEmpty(var) requires one argument.")); evalError(fL1S("isEmpty(var) requires one argument."));
...@@ -1458,17 +1431,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1458,17 +1431,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse; return ReturnFalse;
} }
#ifdef PROEVALUATOR_FULL
case T_MKPATH: { case T_MKPATH: {
if (args.count() != 1) { if (args.count() != 1) {
evalError(fL1S("mkpath(file) requires one argument.")); evalError(fL1S("mkpath(file) requires one argument."));
return ReturnFalse; return ReturnFalse;
} }
#ifdef PROEVALUATOR_FULL
const QString &fn = resolvePath(args.at(0).toQString(m_tmp1)); const QString &fn = resolvePath(args.at(0).toQString(m_tmp1));
if (!QDir::current().mkpath(fn)) { if (!QDir::current().mkpath(fn)) {
evalError(fL1S("Cannot create directory %1.").arg(QDir::toNativeSeparators(fn))); evalError(fL1S("Cannot create directory %1.").arg(QDir::toNativeSeparators(fn)));
return ReturnFalse; return ReturnFalse;
} }
#endif
return ReturnTrue; return ReturnTrue;
} }
case T_WRITE_FILE: { case T_WRITE_FILE: {
...@@ -1476,6 +1450,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1476,6 +1450,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
evalError(fL1S("write_file(name, [content var, [append]]) requires one to three arguments.")); evalError(fL1S("write_file(name, [content var, [append]]) requires one to three arguments."));
return ReturnFalse; return ReturnFalse;
} }
#ifdef PROEVALUATOR_FULL
QIODevice::OpenMode mode = QIODevice::Truncate; QIODevice::OpenMode mode = QIODevice::Truncate;
QString contents; QString contents;
if (args.count() >= 2) { if (args.count() >= 2) {
...@@ -1487,12 +1462,16 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1487,12 +1462,16 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
mode = QIODevice::Append; mode = QIODevice::Append;
} }
return writeFile(QString(), resolvePath(args.at(0).toQString(m_tmp1)), mode, contents); return writeFile(QString(), resolvePath(args.at(0).toQString(m_tmp1)), mode, contents);
#else
return ReturnTrue;
#endif
} }
case T_TOUCH: { case T_TOUCH: {
if (args.count() != 2) { if (args.count() != 2) {
evalError(fL1S("touch(file, reffile) requires two arguments.")); evalError(fL1S("touch(file, reffile) requires two arguments."));
return ReturnFalse; return ReturnFalse;
} }
#ifdef PROEVALUATOR_FULL
const QString &tfn = resolvePath(args.at(0).toQString(m_tmp1)); const QString &tfn = resolvePath(args.at(0).toQString(m_tmp1));
const QString &rfn = resolvePath(args.at(1).toQString(m_tmp2)); const QString &rfn = resolvePath(args.at(1).toQString(m_tmp2));
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
...@@ -1528,6 +1507,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1528,6 +1507,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
} }
SetFileTime(wHand, 0, 0, &ft); SetFileTime(wHand, 0, 0, &ft);
CloseHandle(wHand); CloseHandle(wHand);
#endif
#endif #endif
return ReturnTrue; return ReturnTrue;
} }
...@@ -1536,6 +1516,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1536,6 +1516,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
evalError(fL1S("cache(var, [set|add|sub] [transient] [super], [srcvar]) requires one to three arguments.")); evalError(fL1S("cache(var, [set|add|sub] [transient] [super], [srcvar]) requires one to three arguments."));
return ReturnFalse; return ReturnFalse;
} }
#ifdef PROEVALUATOR_FULL
bool persist = true; bool persist = true;
bool super = false; bool super = false;
enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet; enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet;
...@@ -1661,8 +1642,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ...@@ -1661,8 +1642,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
fn = m_cachefile; fn = m_cachefile;
} }
return writeFile(fL1S("cache "), fn, QIODevice::Append, varstr); return writeFile(fL1S("cache "), fn, QIODevice::Append, varstr);
} #else
return ReturnTrue;
#endif #endif
}
default: default:
evalError(fL1S("Function '%1' is not implemented.").arg(function.toQString(m_tmp1))); evalError(fL1S("Function '%1' is not implemented.").arg(function.toQString(m_tmp1)));
return ReturnFalse; return ReturnFalse;
......
...@@ -126,6 +126,7 @@ void QMakeEvaluator::initStatics() ...@@ -126,6 +126,7 @@ void QMakeEvaluator::initStatics()
statics.strforever = QLatin1String("forever"); statics.strforever = QLatin1String("forever");
statics.strhost_build = QLatin1String("host_build"); statics.strhost_build = QLatin1String("host_build");
statics.strTEMPLATE = ProKey("TEMPLATE"); statics.strTEMPLATE = ProKey("TEMPLATE");
statics.strQMAKE_PLATFORM = ProKey("QMAKE_PLATFORM");
#ifdef PROEVALUATOR_FULL #ifdef PROEVALUATOR_FULL
statics.strREQUIRES = ProKey("REQUIRES"); statics.strREQUIRES = ProKey("REQUIRES");
#endif #endif
...@@ -195,7 +196,6 @@ QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option, ...@@ -195,7 +196,6 @@ QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option,
#ifdef PROEVALUATOR_CUMULATIVE #ifdef PROEVALUATOR_CUMULATIVE
m_skipLevel = 0; m_skipLevel = 0;
#endif #endif
m_loopLevel = 0;
m_listCount = 0; m_listCount = 0;
m_valuemapStack.push(ProValueMap()); m_valuemapStack.push(ProValueMap());
m_valuemapInited = false; m_valuemapInited = false;
...@@ -264,48 +264,55 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil ...@@ -264,48 +264,55 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil
{ {
QString build; QString build;
ProStringList ret; ProStringList ret;
QStack<char> quote;
const ushort SPACE = ' ';
const ushort LPAREN = '(';
const ushort RPAREN = ')';
const ushort SINGLEQUOTE = '\'';
const ushort DOUBLEQUOTE = '"';
const ushort BACKSLASH = '\\';
if (!source) if (!source)
source = currentProFile(); source = currentProFile();
ushort unicode;
const QChar *vals_data = vals.data(); const QChar *vals_data = vals.data();
const int vals_len = vals.length(); const int vals_len = vals.length();
int parens = 0; ushort quote = 0;
bool hadWord = false;
for (int x = 0; x < vals_len; x++) { for (int x = 0; x < vals_len; x++) {
unicode = vals_data[x].unicode(); ushort unicode = vals_data[x].unicode();
if (x != (int)vals_len-1 && unicode == BACKSLASH && if (unicode == quote) {
(vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) { quote = 0;
build += vals_data[x++]; //get that 'escape' continue;
} else if (!quote.isEmpty() && unicode == quote.top()) {
quote.pop();
} else if (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) {
quote.push(unicode);
} else if (unicode == RPAREN) {
--parens;
} else if (unicode == LPAREN) {
++parens;
} }
switch (unicode) {
if (!parens && quote.isEmpty() && vals_data[x] == SPACE) { case '"':
ret << ProString(build).setSource(source); case '\'':
build.clear(); quote = unicode;
} else { hadWord = true;
build += vals_data[x]; continue;
case ' ':
case '\t':
if (!quote) {
if (hadWord) {
ret << ProString(build).setSource(source);
build.clear();
hadWord = false;
}
continue;
}
build += QChar(unicode);
break;
case '\\':
if (x + 1 != vals_len) {
ushort next = vals_data[++x].unicode();
if (next == '\'' || next == '"' || next == '\\')
unicode = next;
else
--x;
}
// fallthrough
default:
hadWord = true;
build += QChar(unicode);
break;
} }
} }
if (!build.isEmpty()) if (hadWord)
ret << ProString(build).setSource(source); ret << ProString(build).setSource(source);
if (parens)
deprecationWarning(fL1S("Unmatched parentheses are deprecated."));
return ret; return ret;
} }
...@@ -454,9 +461,9 @@ void QMakeEvaluator::evaluateExpression( ...@@ -454,9 +461,9 @@ void QMakeEvaluator::evaluateExpression(
break; } break; }
case TokEnvVar: { case TokEnvVar: {
const ProString &var = getStr(tokPtr); const ProString &var = getStr(tokPtr);
const ProStringList &val = split_value_list(m_option->getEnv(var.toQString(m_tmp1))); const ProString &val = ProString(m_option->getEnv(var.toQString(m_tmp1)));
debugMsg(2, "env var %s => %s", dbgStr(var), dbgStrList(val)); debugMsg(2, "env var %s => %s", dbgStr(var), dbgStr(val));
addStrList(val, tok, ret, pending, joined); addStr(val, ret, pending, joined);
break; } break; }
case TokFuncName: { case TokFuncName: {
const ProKey &func = getHashStr(tokPtr); const ProKey &func = getHashStr(tokPtr);
...@@ -683,6 +690,24 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( ...@@ -683,6 +690,24 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
invert = false; invert = false;
curr.clear(); curr.clear();
continue; continue;
case TokReturn:
m_returnValue = curr;
curr.clear();
ret = ReturnReturn;
goto ctrlstm;
case TokBreak:
ret = ReturnBreak;
goto ctrlstm;
case TokNext:
ret = ReturnNext;
ctrlstm:
if (!m_skipLevel && okey != or_op) {
traceMsg("flow control statement '%s', aborting block", dbgReturn(ret));
return ret;
}
traceMsg("skipped flow control statement '%s'", dbgReturn(ret));
okey = false, or_op = true; // force next evaluation
continue;
default: { default: {
const ushort *oTokPtr = --tokPtr; const ushort *oTokPtr = --tokPtr;
evaluateExpression(tokPtr, &curr, false); evaluateExpression(tokPtr, &curr, false);
...@@ -762,7 +787,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( ...@@ -762,7 +787,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
else else
traceMsg("entering loop for %s over %s", dbgKey(variable), dbgStrList(list)); traceMsg("entering loop for %s over %s", dbgKey(variable), dbgStrList(list));
m_loopLevel++;
forever { forever {
if (infinite) { if (infinite) {
if (!variable.isEmpty()) if (!variable.isEmpty())
...@@ -799,7 +823,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( ...@@ -799,7 +823,6 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
} }
} }
do_break: do_break:
m_loopLevel--;
traceMsg("done looping"); traceMsg("done looping");
...@@ -909,6 +932,8 @@ void QMakeEvaluator::visitProVariable( ...@@ -909,6 +932,8 @@ void QMakeEvaluator::visitProVariable(
if (varName == statics.strTEMPLATE) if (varName == statics.strTEMPLATE)
setTemplate(); setTemplate();
else if (varName == statics.strQMAKE_PLATFORM)
updateFeaturePaths();
#ifdef PROEVALUATOR_FULL #ifdef PROEVALUATOR_FULL
else if (varName == statics.strREQUIRES) else if (varName == statics.strREQUIRES)
checkRequirements(values(varName)); checkRequirements(values(varName));
...@@ -1037,7 +1062,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) ...@@ -1037,7 +1062,7 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
forever { forever {
QString superfile = superdir + QLatin1String("/.qmake.super"); QString superfile = superdir + QLatin1String("/.qmake.super");
if (IoUtils::exists(superfile)) { if (IoUtils::exists(superfile)) {
m_superfile = superfile; m_superfile = QDir::cleanPath(superfile);
break; break;
} }
QFileInfo qdfi(superdir); QFileInfo qdfi(superdir);
...@@ -1074,8 +1099,8 @@ bool QMakeEvaluator::prepareProject(const QString &inDir) ...@@ -1074,8 +1099,8 @@ bool QMakeEvaluator::prepareProject(const QString &inDir)
} else { } else {
m_buildRoot = QFileInfo(cachefile).path(); m_buildRoot = QFileInfo(cachefile).path();
} }
m_conffile = conffile; m_conffile = QDir::cleanPath(conffile);
m_cachefile = cachefile; m_cachefile = QDir::cleanPath(cachefile);
} }
no_cache: no_cache:
...@@ -1199,7 +1224,6 @@ bool QMakeEvaluator::loadSpec() ...@@ -1199,7 +1224,6 @@ bool QMakeEvaluator::loadSpec()
} }
if (!loadSpecInternal()) if (!loadSpecInternal())
return false; return false;
updateFeaturePaths(); // The spec extends the feature search path, so rebuild the cache.
if (!m_conffile.isEmpty() if (!m_conffile.isEmpty()
&& !evaluateFile(m_conffile, QMakeHandler::EvalConfigFile, LoadProOnly)) { && !evaluateFile(m_conffile, QMakeHandler::EvalConfigFile, LoadProOnly)) {
return false; return false;
...@@ -1589,8 +1613,6 @@ ProStringList QMakeEvaluator::evaluateFunction( ...@@ -1589,8 +1613,6 @@ ProStringList QMakeEvaluator::evaluateFunction(
} else { } else {
m_valuemapStack.push(ProValueMap()); m_valuemapStack.push(ProValueMap());
m_locationStack.push(m_current); m_locationStack.push(m_current);
int loopLevel = m_loopLevel;
m_loopLevel = 0;
ProStringList args; ProStringList args;
for (int i = 0; i < argumentsList.count(); ++i) { for (int i = 0; i < argumentsList.count(); ++i) {
...@@ -1603,7 +1625,6 @@ ProStringList QMakeEvaluator::evaluateFunction( ...@@ -1603,7 +1625,6 @@ ProStringList QMakeEvaluator::evaluateFunction(
ret = m_returnValue; ret = m_returnValue;
m_returnValue.clear(); m_returnValue.clear();
m_loopLevel = loopLevel;
m_current = m_locationStack.pop(); m_current = m_locationStack.pop();
m_valuemapStack.pop(); m_valuemapStack.pop();
} }
......
...@@ -233,7 +233,6 @@ public: ...@@ -233,7 +233,6 @@ public:
static void removeEach(ProStringList *varlist, const ProStringList &value); static void removeEach(ProStringList *varlist, const ProStringList &value);
QMakeEvaluator *m_caller; QMakeEvaluator *m_caller;
int m_loopLevel; // To report unexpected break() and next()s
#ifdef PROEVALUATOR_CUMULATIVE #ifdef PROEVALUATOR_CUMULATIVE
bool m_cumulative; bool m_cumulative;
int m_skipLevel; int m_skipLevel;
......
...@@ -89,6 +89,7 @@ struct QMakeStatics { ...@@ -89,6 +89,7 @@ struct QMakeStatics {
QString strforever; QString strforever;
QString strhost_build; QString strhost_build;
ProKey strTEMPLATE; ProKey strTEMPLATE;
ProKey strQMAKE_PLATFORM;
#ifdef PROEVALUATOR_FULL #ifdef PROEVALUATOR_FULL
ProKey strREQUIRES; ProKey strREQUIRES;
#endif #endif
......
...@@ -115,7 +115,6 @@ QMakeGlobals::QMakeGlobals() ...@@ -115,7 +115,6 @@ QMakeGlobals::QMakeGlobals()
dirlist_sep = QLatin1Char(':'); dirlist_sep = QLatin1Char(':');
dir_sep = QLatin1Char('/'); dir_sep = QLatin1Char('/');
#endif #endif
qmakespec = getEnv(QLatin1String("QMAKESPEC"));
} }
QMakeGlobals::~QMakeGlobals() QMakeGlobals::~QMakeGlobals()
......
...@@ -108,6 +108,9 @@ static struct { ...@@ -108,6 +108,9 @@ static struct {
QString strdefineTest; QString strdefineTest;
QString strdefineReplace; QString strdefineReplace;
QString stroption; QString stroption;
QString strreturn;
QString strnext;
QString strbreak;
QString strhost_build; QString strhost_build;
QString strLINE; QString strLINE;
QString strFILE; QString strFILE;
...@@ -128,6 +131,9 @@ void QMakeParser::initialize() ...@@ -128,6 +131,9 @@ void QMakeParser::initialize()
statics.strdefineTest = QLatin1String("defineTest"); statics.strdefineTest = QLatin1String("defineTest");
statics.strdefineReplace = QLatin1String("defineReplace"); statics.strdefineReplace = QLatin1String("defineReplace");
statics.stroption = QLatin1String("option"); statics.stroption = QLatin1String("option");
statics.strreturn = QLatin1String("return");
statics.strnext = QLatin1String("next");
statics.strbreak = QLatin1String("break");
statics.strhost_build = QLatin1String("host_build"); statics.strhost_build = QLatin1String("host_build");
statics.strLINE = QLatin1String("_LINE_"); statics.strLINE = QLatin1String("_LINE_");
statics.strFILE = QLatin1String("_FILE_"); statics.strFILE = QLatin1String("_FILE_");
...@@ -874,9 +880,11 @@ void QMakeParser::putLineMarker(ushort *&tokPtr) ...@@ -874,9 +880,11 @@ void QMakeParser::putLineMarker(ushort *&tokPtr)
void QMakeParser::enterScope(ushort *&tokPtr, bool special, ScopeState state) void QMakeParser::enterScope(ushort *&tokPtr, bool special, ScopeState state)
{ {
uchar nest = m_blockstack.top().nest;
m_blockstack.resize(m_blockstack.size() + 1); m_blockstack.resize(m_blockstack.size() + 1);
m_blockstack.top().special = special; m_blockstack.top().special = special;
m_blockstack.top().start = tokPtr; m_blockstack.top().start = tokPtr;
m_blockstack.top().nest = nest;
tokPtr += 2; tokPtr += 2;
m_state = state; m_state = state;
m_canElse = false; m_canElse = false;
...@@ -1017,13 +1025,14 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg ...@@ -1017,13 +1025,14 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
const QString *defName; const QString *defName;
ushort defType; ushort defType;
if (m_tmp == statics.strfor) { if (m_tmp == statics.strfor) {
flushCond(tokPtr);
putLineMarker(tokPtr);
if (m_invert || m_operator == OrOperator) { if (m_invert || m_operator == OrOperator) {
// '|' could actually work reasonably, but qmake does nonsense here. // '|' could actually work reasonably, but qmake does nonsense here.
parseError(fL1S("Unexpected operator in front of for().")); parseError(fL1S("Unexpected operator in front of for()."));
bogusTest(tokPtr);
return; return;
} }
flushCond(tokPtr);
putLineMarker(tokPtr);
if (*uce == (TokLiteral|TokNewStr)) { if (*uce == (TokLiteral|TokNewStr)) {
nlen = uce[1]; nlen = uce[1];
uc = uce + 2 + nlen; uc = uce + 2 + nlen;
...@@ -1037,6 +1046,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg ...@@ -1037,6 +1046,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
didFor: didFor:
putTok(tokPtr, TokValueTerminator); putTok(tokPtr, TokValueTerminator);
enterScope(tokPtr, true, StCtrl); enterScope(tokPtr, true, StCtrl);
m_blockstack.top().nest |= NestLoop;
return; return;
} else if (*uc == TokArgSeparator && argc == 2) { } else if (*uc == TokArgSeparator && argc == 2) {
// for(var, something) // for(var, something)
...@@ -1066,12 +1076,13 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg ...@@ -1066,12 +1076,13 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
defName = &statics.strdefineTest; defName = &statics.strdefineTest;
defType = TokTestDef; defType = TokTestDef;
deffunc: deffunc:
flushScopes(tokPtr);
putLineMarker(tokPtr);
if (m_invert) { if (m_invert) {
parseError(fL1S("Unexpected operator in front of function definition.")); parseError(fL1S("Unexpected operator in front of function definition."));
bogusTest(tokPtr);
return; return;
} }
flushScopes(tokPtr);
putLineMarker(tokPtr);
if (*uce == (TokLiteral|TokNewStr)) { if (*uce == (TokLiteral|TokNewStr)) {
uint nlen = uce[1]; uint nlen = uce[1];
if (uce[nlen + 2] == TokFuncTerminator) { if (uce[nlen + 2] == TokFuncTerminator) {
...@@ -1082,15 +1093,59 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg ...@@ -1082,15 +1093,59 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
putTok(tokPtr, defType); putTok(tokPtr, defType);
putHashStr(tokPtr, uce + 2, nlen); putHashStr(tokPtr, uce + 2, nlen);
enterScope(tokPtr, true, StCtrl); enterScope(tokPtr, true, StCtrl);
m_blockstack.top().nest = NestFunction;
return; return;
} }
} }
parseError(fL1S("%1(function) requires one literal argument.").arg(*defName)); parseError(fL1S("%1(function) requires one literal argument.").arg(*defName));
return; return;
} else if (m_tmp == statics.strreturn) {
if (m_blockstack.top().nest & NestFunction) {
if (argc > 1) {
parseError(fL1S("return() requires zero or one argument."));
bogusTest(tokPtr);
return;
}
} else {
if (*uce != TokFuncTerminator) {
parseError(fL1S("Top-level return() requires zero arguments."));
bogusTest(tokPtr);
return;
}
}
defType = TokReturn;
goto ctrlstm2;
} else if (m_tmp == statics.strnext) {
defType = TokNext;
goto ctrlstm;
} else if (m_tmp == statics.strbreak) {
defType = TokBreak;
ctrlstm:
if (*uce != TokFuncTerminator) {
parseError(fL1S("%1() requires zero arguments.").arg(m_tmp));
bogusTest(tokPtr);
return;
}
if (!(m_blockstack.top().nest & NestLoop)) {
parseError(fL1S("Unexpected %1().").arg(m_tmp));
bogusTest(tokPtr);
return;
}
ctrlstm2:
if (m_invert) {
parseError(fL1S("Unexpected NOT operator in front of %1().").arg(m_tmp));
bogusTest(tokPtr);
return;
}
finalizeTest(tokPtr);
putBlock(tokPtr, uce, ptr - uce - 1); // Only for TokReturn
putTok(tokPtr, defType);
return;
} else if (m_tmp == statics.stroption) { } else if (m_tmp == statics.stroption) {
if (m_state != StNew || m_blockstack.top().braceLevel || m_blockstack.size() > 1 if (m_state != StNew || m_blockstack.top().braceLevel || m_blockstack.size() > 1
|| m_invert || m_operator != NoOperator) { || m_invert || m_operator != NoOperator) {
parseError(fL1S("option() must appear outside any control structures.")); parseError(fL1S("option() must appear outside any control structures."));
bogusTest(tokPtr);
return; return;
} }
if (*uce == (TokLiteral|TokNewStr)) { if (*uce == (TokLiteral|TokNewStr)) {
......
...@@ -97,13 +97,20 @@ public: ...@@ -97,13 +97,20 @@ public:
void discardFileFromCache(const QString &fileName); void discardFileFromCache(const QString &fileName);
private: private:
enum ScopeNesting {
NestNone = 0,
NestLoop = 1,
NestFunction = 2
};
struct BlockScope { struct BlockScope {
BlockScope() : start(0), braceLevel(0), special(false), inBranch(false) {} BlockScope() : start(0), braceLevel(0), special(false), inBranch(false), nest(NestNone) {}
BlockScope(const BlockScope &other) { *this = other; } BlockScope(const BlockScope &other) { *this = other; }
ushort *start; // Where this block started; store length here ushort *start; // Where this block started; store length here
int braceLevel; // Nesting of braces in scope int braceLevel; // Nesting of braces in scope
bool special; // Single-line conditionals inside loops, etc. cannot have else branches bool special; // Single-line conditionals inside loops, etc. cannot have else branches
bool inBranch; // The 'else' branch of the previous TokBranch is still open bool inBranch; // The 'else' branch of the previous TokBranch is still open
uchar nest; // Into what control structures we are nested
}; };
enum ScopeState { enum ScopeState {
......
...@@ -47,7 +47,9 @@ ...@@ -47,7 +47,9 @@
#include <QtGui/QMouseEvent> #include <QtGui/QMouseEvent>
#include <QtGui/QRegion> #include <QtGui/QRegion>
#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#endif
#include "math.h" #include "math.h"
......
...@@ -2,3 +2,4 @@ tst_lupdate ...@@ -2,3 +2,4 @@ tst_lupdate
testdata/*/*.ts testdata/*/*.ts
testdata/*/*/*.ts testdata/*/*/*.ts
testdata/*/*/*/*.ts testdata/*/*/*/*.ts
testdata/good/*/.qmake.cache
...@@ -122,19 +122,12 @@ static bool prepareMatch(const QString &expect, QString *tmpl, int *require, int ...@@ -122,19 +122,12 @@ static bool prepareMatch(const QString &expect, QString *tmpl, int *require, int
return true; return true;
} }
void tst_lupdate::doCompare(const QStringList &_actual, const QString &expectedFn, bool err) void tst_lupdate::doCompare(const QStringList &actual, const QString &expectedFn, bool err)
{ {
QFile file(expectedFn); QFile file(expectedFn);
QVERIFY2(file.open(QIODevice::ReadOnly | QIODevice::Text), qPrintable(expectedFn)); QVERIFY2(file.open(QIODevice::ReadOnly | QIODevice::Text), qPrintable(expectedFn));
QStringList expected = QString(file.readAll()).split('\n'); QStringList expected = QString(file.readAll()).split('\n');
QStringList actual;
actual.reserve(_actual.size());
QRegExp niRx(".*:(Function '\\w+' is not implemented|'\\w+' is not a recognized replace function)");
foreach (const QString &a, _actual)
if (!niRx.exactMatch(a))
actual << a;
int ei = 0, ai = 0, em = expected.size(), am = actual.size(); int ei = 0, ai = 0, em = expected.size(), am = actual.size();
int oei = 0, oai = 0, oem = em, oam = am; int oei = 0, oai = 0, oem = em, oam = am;
int require = 0, accept = 0; int require = 0, accept = 0;
...@@ -287,6 +280,10 @@ void tst_lupdate::good() ...@@ -287,6 +280,10 @@ void tst_lupdate::good()
QVERIFY2(QFile::copy(beforetsfile, genTs), qPrintable(beforetsfile)); QVERIFY2(QFile::copy(beforetsfile, genTs), qPrintable(beforetsfile));
} }
file.setFileName(workDir + QStringLiteral("/.qmake.cache"));
QVERIFY(file.open(QIODevice::WriteOnly));
file.close();
if (lupdatecmd.isEmpty()) if (lupdatecmd.isEmpty())
lupdatecmd = QLatin1String("project.pro"); lupdatecmd = QLatin1String("project.pro");
lupdatecmd.prepend("-silent "); lupdatecmd.prepend("-silent ");
......