diff options
Diffstat (limited to 'qmake/library')
-rw-r--r-- | qmake/library/ioutils.cpp | 64 | ||||
-rw-r--r-- | qmake/library/ioutils.h | 14 | ||||
-rw-r--r-- | qmake/library/proitems.cpp | 35 | ||||
-rw-r--r-- | qmake/library/proitems.h | 19 | ||||
-rw-r--r-- | qmake/library/qmake_global.h | 14 | ||||
-rw-r--r-- | qmake/library/qmakebuiltins.cpp | 34 | ||||
-rw-r--r-- | qmake/library/qmakeevaluator.cpp | 112 | ||||
-rw-r--r-- | qmake/library/qmakeevaluator.h | 18 | ||||
-rw-r--r-- | qmake/library/qmakeevaluator_p.h | 14 | ||||
-rw-r--r-- | qmake/library/qmakeglobals.cpp | 14 | ||||
-rw-r--r-- | qmake/library/qmakeglobals.h | 14 | ||||
-rw-r--r-- | qmake/library/qmakeparser.cpp | 436 | ||||
-rw-r--r-- | qmake/library/qmakeparser.h | 33 | ||||
-rw-r--r-- | qmake/library/qmakevfs.cpp | 14 | ||||
-rw-r--r-- | qmake/library/qmakevfs.h | 14 |
15 files changed, 603 insertions, 246 deletions
diff --git a/qmake/library/ioutils.cpp b/qmake/library/ioutils.cpp index 8dd88bf9a5..04be215246 100644 --- a/qmake/library/ioutils.cpp +++ b/qmake/library/ioutils.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -100,11 +100,18 @@ QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName) } inline static +bool isSpecialChar(ushort c, const uchar (&iqm)[16]) +{ + if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)))) + return true; + return false; +} + +inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16]) { for (int x = arg.length() - 1; x >= 0; --x) { - ushort c = arg.unicode()[x].unicode(); - if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)))) + if (isSpecialChar(arg.unicode()[x].unicode(), iqm)) return true; } return false; @@ -119,7 +126,7 @@ QString IoUtils::shellQuoteUnix(const QString &arg) }; // 0-32 \'"$`<>|;&(){}*?#!~[] if (!arg.length()) - return QString::fromLatin1("\"\""); + return QString::fromLatin1("''"); QString ret(arg); if (hasSpecialChars(ret, iqm)) { @@ -140,23 +147,38 @@ QString IoUtils::shellQuoteWin(const QString &arg) 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 }; + // Shell meta chars that need escaping. + static const uchar ism[] = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 + }; // &()<>^| if (!arg.length()) return QString::fromLatin1("\"\""); QString ret(arg); if (hasSpecialChars(ret, iqm)) { - // Quotes are escaped and their preceding backslashes are doubled. - // It's impossible to escape anything inside a quoted string on cmd - // level, so the outer quoting must be "suspended". - ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\"")); - // The argument must not end with a \ since this would be interpreted - // as escaping the quote -- rather put the \ behind the quote: e.g. - // rather use "foo"\ than "foo\" - int i = ret.length(); - while (i > 0 && ret.at(i - 1) == QLatin1Char('\\')) - --i; - ret.insert(i, QLatin1Char('"')); + // The process-level standard quoting allows escaping quotes with backslashes (note + // that backslashes don't escape themselves, unless they are followed by a quote). + // Consequently, quotes are escaped and their preceding backslashes are doubled. + ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); + // Trailing backslashes must be doubled as well, as they are followed by a quote. + ret.replace(QRegExp(QLatin1String("(\\\\+)$")), QLatin1String("\\1\\1")); + // However, the shell also interprets the command, and no backslash-escaping exists + // there - a quote always toggles the quoting state, but is nonetheless passed down + // to the called process verbatim. In the unquoted state, the circumflex escapes + // meta chars (including itself and quotes), and is removed from the command. + bool quoted = true; + for (int i = 0; i < ret.length(); i++) { + QChar c = ret.unicode()[i]; + if (c.unicode() == '"') + quoted = !quoted; + else if (!quoted && isSpecialChar(c.unicode(), ism)) + ret.insert(i++, QLatin1Char('^')); + } + if (!quoted) + ret.append(QLatin1Char('^')); + ret.append(QLatin1Char('"')); ret.prepend(QLatin1Char('"')); } return ret; diff --git a/qmake/library/ioutils.h b/qmake/library/ioutils.h index ba6e2708cb..b726ce3e09 100644 --- a/qmake/library/ioutils.h +++ b/qmake/library/ioutils.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ diff --git a/qmake/library/proitems.cpp b/qmake/library/proitems.cpp index 97cc590d84..e780259417 100644 --- a/qmake/library/proitems.cpp +++ b/qmake/library/proitems.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -386,6 +386,20 @@ void ProStringList::removeAll(const char *str) remove(i); } +void ProStringList::removeEach(const ProStringList &value) +{ + foreach (const ProString &str, value) + if (!str.isEmpty()) + removeAll(str); +} + +void ProStringList::removeEmpty() +{ + for (int i = size(); --i >= 0;) + if (at(i).isEmpty()) + remove(i); +} + void ProStringList::removeDuplicates() { int n = size(); @@ -405,6 +419,13 @@ void ProStringList::removeDuplicates() erase(begin() + j, end()); } +void ProStringList::insertUnique(const ProStringList &value) +{ + foreach (const ProString &str, value) + if (!str.isEmpty() && !contains(str)) + append(str); +} + ProStringList::ProStringList(const QStringList &list) { reserve(list.size()); diff --git a/qmake/library/proitems.h b/qmake/library/proitems.h index 28178ac9a6..d31367361d 100644 --- a/qmake/library/proitems.h +++ b/qmake/library/proitems.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -138,6 +138,7 @@ public: int toInt(bool *ok = 0, int base = 10) const { return toQString().toInt(ok, base); } // XXX optimize short toShort(bool *ok = 0, int base = 10) const { return toQString().toShort(ok, base); } // XXX optimize + uint hash() const { return m_hash; } static uint hash(const QChar *p, int n); ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, m_offset, m_length); } @@ -239,9 +240,13 @@ public: QString join(const QString &sep) const; QString join(QChar sep) const; + void insertUnique(const ProStringList &value); + void removeAll(const ProString &str); void removeAll(const char *str); + void removeEach(const ProStringList &value); void removeAt(int idx) { remove(idx); } + void removeEmpty(); void removeDuplicates(); bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; diff --git a/qmake/library/qmake_global.h b/qmake/library/qmake_global.h index 3bb9d9955f..8f2eb5fd33 100644 --- a/qmake/library/qmake_global.h +++ b/qmake/library/qmake_global.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index b735822806..e384d26f4c 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -218,8 +218,8 @@ static QString windowsErrorCode() } #endif -static QString -quoteValue(const ProString &val) +QString +QMakeEvaluator::quoteValue(const ProString &val) { QString ret; ret.reserve(val.size()); @@ -1202,15 +1202,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( VisitReturn ret = ReturnFalse; ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep), m_current.pro->fileName(), m_current.line); - if (pro) { - if (m_cumulative || pro->isOk()) { - m_locationStack.push(m_current); - visitProBlock(pro, pro->tokPtr()); - ret = ReturnTrue; // This return value is not too useful, but that's qmake - m_current = m_locationStack.pop(); - } - pro->deref(); + if (m_cumulative || pro->isOk()) { + m_locationStack.push(m_current); + visitProBlock(pro, pro->tokPtr()); + ret = ReturnTrue; // This return value is not too useful, but that's qmake + m_current = m_locationStack.pop(); } + pro->deref(); return ret; } case T_IF: { @@ -1689,7 +1687,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( if (mode == CacheAdd) newval += diffval; else - removeEach(&newval, diffval); + newval.removeEach(diffval); } if (oldval != newval) { if (target != TargetStash || !m_stashfile.isEmpty()) { diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp index 9b5291a08e..5c9dc45f3a 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -58,6 +58,9 @@ #ifdef Q_OS_UNIX #include <unistd.h> #include <sys/utsname.h> +# ifdef Q_OS_BSD4 +# include <sys/sysctl.h> +# endif #else #include <windows.h> #endif @@ -70,6 +73,39 @@ QT_BEGIN_NAMESPACE #define fL1S(s) QString::fromLatin1(s) +// we can't use QThread in qmake +// this function is a merger of QThread::idealThreadCount from qthread_win.cpp and qthread_unix.cpp +static int idealThreadCount() +{ +#ifdef PROEVALUATOR_THREAD_SAFE + return QThread::idealThreadCount(); +#elif defined(Q_OS_WIN) + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; +#else + // there are a couple more definitions in the Unix QThread::idealThreadCount, but + // we don't need them all here + int cores = 1; +# if defined(Q_OS_BSD4) + // FreeBSD, OpenBSD, NetBSD, BSD/OS, Mac OS X + size_t len = sizeof(cores); + int mib[2]; + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) { + perror("sysctl"); + } +# elif defined(_SC_NPROCESSORS_ONLN) + // the rest: Linux, Solaris, AIX, Tru64 + cores = (int)sysconf(_SC_NPROCESSORS_ONLN); + if (cores == -1) + return 1; +# endif + return cores; +#endif +} + QMakeBaseKey::QMakeBaseKey(const QString &_root, const QString &_stash, bool _hostBuild) : root(_root), stash(_stash), hostBuild(_hostBuild) @@ -314,34 +350,6 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil return ret; } -static void zipEmpty(ProStringList *value) -{ - for (int i = value->size(); --i >= 0;) - if (value->at(i).isEmpty()) - value->remove(i); -} - -static void insertUnique(ProStringList *varlist, const ProStringList &value) -{ - foreach (const ProString &str, value) - if (!str.isEmpty() && !varlist->contains(str)) - varlist->append(str); -} - -static void removeAll(ProStringList *varlist, const ProString &value) -{ - for (int i = varlist->size(); --i >= 0; ) - if (varlist->at(i) == value) - varlist->remove(i); -} - -void QMakeEvaluator::removeEach(ProStringList *varlist, const ProStringList &value) -{ - foreach (const ProString &str, value) - if (!str.isEmpty()) - removeAll(varlist, str); -} - static void replaceInList(ProStringList *varlist, const QRegExp ®exp, const QString &replace, bool global, QString &tmp) { @@ -880,24 +888,24 @@ void QMakeEvaluator::visitProVariable( switch (tok) { default: // whatever - cannot happen case TokAssign: // = - zipEmpty(&varVal); + varVal.removeEmpty(); // FIXME: add check+warning about accidental value removal. // This may be a bit too noisy, though. m_valuemapStack.top()[varName] = varVal; debugMsg(2, "assigning"); break; case TokAppendUnique: // *= - insertUnique(&valuesRef(varName), varVal); + valuesRef(varName).insertUnique(varVal); debugMsg(2, "appending unique"); break; case TokAppend: // += - zipEmpty(&varVal); + varVal.removeEmpty(); valuesRef(varName) += varVal; debugMsg(2, "appending"); break; case TokRemove: // -= if (!m_cumulative) { - removeEach(&valuesRef(varName), varVal); + valuesRef(varName).removeEach(varVal); } else { // We are stingy with our values. } @@ -998,6 +1006,7 @@ void QMakeEvaluator::loadDefaults() vars[ProKey("QMAKE_QMAKE")] << ProString(m_option->qmake_abslocation); if (!m_option->qmake_args.isEmpty()) vars[ProKey("QMAKE_ARGS")] = ProStringList(m_option->qmake_args); + vars[ProKey("QMAKE_HOST.cpu_count")] = ProString(QString::number(idealThreadCount())); #if defined(Q_OS_WIN32) vars[ProKey("QMAKE_HOST.os")] << ProString("Windows"); @@ -1270,14 +1279,13 @@ void QMakeEvaluator::setupProject() void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) { if (!cmds.isEmpty()) { - if (ProFile *pro = m_parser->parsedProBlock(cmds, where, -1)) { - if (pro->isOk()) { - m_locationStack.push(m_current); - visitProBlock(pro, pro->tokPtr()); - m_current = m_locationStack.pop(); - } - pro->deref(); + ProFile *pro = m_parser->parsedProBlock(cmds, where, -1); + if (pro->isOk()) { + m_locationStack.push(m_current); + visitProBlock(pro, pro->tokPtr()); + m_current = m_locationStack.pop(); } + pro->deref(); } } @@ -1757,14 +1765,12 @@ bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &whe { bool ret = false; ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar); - if (pro) { - if (pro->isOk()) { - m_locationStack.push(m_current); - ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue; - m_current = m_locationStack.pop(); - } - pro->deref(); + if (pro->isOk()) { + m_locationStack.push(m_current); + ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue; + m_current = m_locationStack.pop(); } + pro->deref(); return ret; } diff --git a/qmake/library/qmakeevaluator.h b/qmake/library/qmakeevaluator.h index 73fd5bb82f..4f2acf25ee 100644 --- a/qmake/library/qmakeevaluator.h +++ b/qmake/library/qmakeevaluator.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -243,8 +243,6 @@ public: #endif QByteArray getCommandOutput(const QString &args) const; - static void removeEach(ProStringList *varlist, const ProStringList &value); - QMakeEvaluator *m_caller; #ifdef PROEVALUATOR_CUMULATIVE bool m_cumulative; @@ -254,6 +252,8 @@ public: enum { m_skipLevel = 0 }; #endif + static QString quoteValue(const ProString &val); + #ifdef PROEVALUATOR_DEBUG void debugMsgInternal(int level, const char *fmt, ...) const; void traceMsgInternal(const char *fmt, ...) const; diff --git a/qmake/library/qmakeevaluator_p.h b/qmake/library/qmakeevaluator_p.h index dd63bcea02..e000fc9cf5 100644 --- a/qmake/library/qmakeevaluator_p.h +++ b/qmake/library/qmakeevaluator_p.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ diff --git a/qmake/library/qmakeglobals.cpp b/qmake/library/qmakeglobals.cpp index aeb8a6c803..55ce404410 100644 --- a/qmake/library/qmakeglobals.cpp +++ b/qmake/library/qmakeglobals.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ diff --git a/qmake/library/qmakeglobals.h b/qmake/library/qmakeglobals.h index 6950d32807..7c77450523 100644 --- a/qmake/library/qmakeglobals.h +++ b/qmake/library/qmakeglobals.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ diff --git a/qmake/library/qmakeparser.cpp b/qmake/library/qmakeparser.cpp index 3065d4dd5a..3fd7957bc0 100644 --- a/qmake/library/qmakeparser.cpp +++ b/qmake/library/qmakeparser.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -209,10 +209,7 @@ ProFile *QMakeParser::parsedProBlock( const QString &contents, const QString &name, int line, SubGrammar grammar) { ProFile *pro = new ProFile(name); - if (!read(pro, contents, line, grammar)) { - delete pro; - pro = 0; - } + read(pro, contents, line, grammar); return pro; } @@ -232,7 +229,8 @@ bool QMakeParser::read(ProFile *pro, ParseFlags flags) fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr)); return false; } - return read(pro, content, 1, FullGrammar); + read(pro, content, 1, FullGrammar); + return true; } void QMakeParser::putTok(ushort *&tokPtr, ushort tok) @@ -272,7 +270,7 @@ void QMakeParser::finalizeHashStr(ushort *buf, uint len) buf[-2] = (ushort)(hash >> 16); } -bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar) +void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar) { m_proFile = pro; m_lineNo = line; @@ -322,7 +320,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra m_canElse = false; freshLine: m_state = StNew; - m_invert = false; + m_invert = 0; m_operator = NoOperator; m_markLine = m_lineNo; m_inError = false; @@ -579,7 +577,6 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra parseError(fL1S("Missing %1 terminator [found %2]") .arg(QChar(term)) .arg(c ? QString(c) : QString::fromLatin1("end-of-line"))); - pro->setOk(false); m_inError = true; // Just parse on, as if there was a terminator ... } else { @@ -606,7 +603,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra quote = 0; goto nextChr; } else if (c == '!' && ptr == xprPtr && context == CtxTest) { - m_invert ^= true; + m_invert++; goto nextChr; } } else if (c == '\'' || c == '"') { @@ -663,20 +660,20 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra parseError(fL1S("Extra characters after test expression.")); else parseError(fL1S("Opening parenthesis without prior test name.")); - pro->setOk(false); ptr = buf; // Put empty function name } *ptr++ = TokTestCall; term = ':'; goto funcCall; } else if (c == '!' && ptr == xprPtr) { - m_invert ^= true; + m_invert++; goto nextChr; } else if (c == ':') { FLUSH_LHS_LITERAL(); finalizeCond(tokPtr, buf, ptr, wordCount); + warnOperator("in front of AND operator"); if (m_state == StNew) - parseError(fL1S("And operator without prior condition.")); + parseError(fL1S("AND operator without prior condition.")); else m_operator = AndOperator; nextItem: @@ -685,26 +682,33 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra } else if (c == '|') { FLUSH_LHS_LITERAL(); finalizeCond(tokPtr, buf, ptr, wordCount); + warnOperator("in front of OR operator"); if (m_state != StCond) - parseError(fL1S("Or operator without prior condition.")); + parseError(fL1S("OR operator without prior condition.")); else m_operator = OrOperator; goto nextItem; } else if (c == '{') { FLUSH_LHS_LITERAL(); finalizeCond(tokPtr, buf, ptr, wordCount); + if (m_operator == AndOperator) { + languageWarning(fL1S("Excess colon in front of opening brace.")); + m_operator = NoOperator; + } + failOperator("in front of opening brace"); flushCond(tokPtr); + m_state = StNew; // Reset possible StCtrl, so colons get rejected. ++m_blockstack.top().braceLevel; - if (grammar == TestGrammar) { + if (grammar == TestGrammar) parseError(fL1S("Opening scope not permitted in this context.")); - pro->setOk(false); - } goto nextItem; } else if (c == '}') { FLUSH_LHS_LITERAL(); finalizeCond(tokPtr, buf, ptr, wordCount); - flushScopes(tokPtr); + m_state = StNew; // De-facto newline closeScope: + flushScopes(tokPtr); + failOperator("in front of closing brace"); if (!m_blockstack.top().braceLevel) { parseError(fL1S("Excess closing brace.")); } else if (!--m_blockstack.top().braceLevel @@ -736,13 +740,12 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra doOp: FLUSH_LHS_LITERAL(); flushCond(tokPtr); + acceptColon("in front of assignment"); putLineMarker(tokPtr); if (grammar == TestGrammar) { parseError(fL1S("Assignment not permitted in this context.")); - pro->setOk(false); } else if (wordCount != 1) { parseError(fL1S("Assignment needs exactly one word on the left hand side.")); - pro->setOk(false); // Put empty variable name. } else { putBlock(tokPtr, buf, ptr - buf); @@ -811,7 +814,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra } else if (context == CtxPureValue) { putTok(tokPtr, TokValueTerminator); } else { - bogusTest(tokPtr); + bogusTest(tokPtr, QString()); } } else if (context == CtxValue) { FLUSH_VALUE_LIST(); @@ -822,6 +825,7 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra putTok(tokPtr, TokValueTerminator); } else { finalizeCond(tokPtr, buf, ptr, wordCount); + warnOperator("at end of line"); } if (!cur) break; @@ -837,15 +841,12 @@ bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra } flushScopes(tokPtr); - if (m_blockstack.size() > 1) { + if (m_blockstack.size() > 1 || m_blockstack.top().braceLevel) parseError(fL1S("Missing closing brace(s).")); - pro->setOk(false); - } while (m_blockstack.size()) leaveScope(tokPtr); tokBuff.resize(tokPtr - (ushort *)tokBuff.constData()); // Reserved capacity stays *pro->itemsRef() = tokBuff; - return true; #undef FLUSH_VALUE_LIST #undef FLUSH_LITERAL @@ -918,39 +919,90 @@ void QMakeParser::flushCond(ushort *&tokPtr) } } -void QMakeParser::finalizeTest(ushort *&tokPtr) +void QMakeParser::warnOperator(const char *msg) { - flushScopes(tokPtr); - putLineMarker(tokPtr); - if (m_operator != NoOperator) { - putTok(tokPtr, (m_operator == AndOperator) ? TokAnd : TokOr); + if (m_invert) { + languageWarning(fL1S("Stray NOT operator %1.").arg(fL1S(msg))); + m_invert = 0; + } + if (m_operator == AndOperator) { + languageWarning(fL1S("Stray AND operator %1.").arg(fL1S(msg))); + m_operator = NoOperator; + } else if (m_operator == OrOperator) { + languageWarning(fL1S("Stray OR operator %1.").arg(fL1S(msg))); m_operator = NoOperator; } +} + +bool QMakeParser::failOperator(const char *msg) +{ + bool fail = false; if (m_invert) { - putTok(tokPtr, TokNot); - m_invert = false; + parseError(fL1S("Unexpected NOT operator %1.").arg(fL1S(msg))); + m_invert = 0; + fail = true; + } + if (m_operator == AndOperator) { + parseError(fL1S("Unexpected AND operator %1.").arg(fL1S(msg))); + m_operator = NoOperator; + fail = true; + } else if (m_operator == OrOperator) { + parseError(fL1S("Unexpected OR operator %1.").arg(fL1S(msg))); + m_operator = NoOperator; + fail = true; + } + return fail; +} + +bool QMakeParser::acceptColon(const char *msg) +{ + if (m_operator == AndOperator) + m_operator = NoOperator; + return !failOperator(msg); +} + +void QMakeParser::putOperator(ushort *&tokPtr) +{ + if (m_operator== AndOperator) { + // A colon must be used after else and for() if no brace is used, + // but in this case it is obviously not a binary operator. + if (m_state == StCond) + putTok(tokPtr, TokAnd); + m_operator = NoOperator; + } else if (m_operator == OrOperator) { + putTok(tokPtr, TokOr); + m_operator = NoOperator; } +} + +void QMakeParser::finalizeTest(ushort *&tokPtr) +{ + flushScopes(tokPtr); + putLineMarker(tokPtr); + putOperator(tokPtr); + if (m_invert & 1) + putTok(tokPtr, TokNot); + m_invert = 0; m_state = StCond; m_canElse = true; } -void QMakeParser::bogusTest(ushort *&tokPtr) +void QMakeParser::bogusTest(ushort *&tokPtr, const QString &msg) { + if (!msg.isEmpty()) + parseError(msg); flushScopes(tokPtr); m_operator = NoOperator; - m_invert = false; + m_invert = 0; m_state = StCond; m_canElse = true; - m_proFile->setOk(false); } void QMakeParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount) { if (wordCount != 1) { - if (wordCount) { - parseError(fL1S("Extra characters after test expression.")); - bogusTest(tokPtr); - } + if (wordCount) + bogusTest(tokPtr, fL1S("Extra characters after test expression.")); return; } @@ -961,10 +1013,8 @@ void QMakeParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wor if (uce == ptr) { m_tmp.setRawData((QChar *)uc + 4, nlen); if (!m_tmp.compare(statics.strelse, Qt::CaseInsensitive)) { - if (m_invert || m_operator != NoOperator) { - parseError(fL1S("Unexpected operator in front of else.")); + if (failOperator("in front of else")) return; - } BlockScope &top = m_blockstack.top(); if (m_canElse && (!top.special || top.braceLevel)) { // A list of tests (the last one likely with side effects), @@ -1009,18 +1059,18 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg const QString *defName; ushort defType; if (m_tmp == statics.strfor) { - if (m_invert || m_operator == OrOperator) { - // '|' could actually work reasonably, but qmake does nonsense here. - parseError(fL1S("Unexpected operator in front of for().")); - bogusTest(tokPtr); + if (!acceptColon("in front of for()")) { + bogusTest(tokPtr, QString()); return; } flushCond(tokPtr); putLineMarker(tokPtr); + --ptr; + Q_ASSERT(*ptr == TokFuncTerminator); if (*uce == (TokLiteral|TokNewStr)) { nlen = uce[1]; uc = uce + 2 + nlen; - if (*uc == TokFuncTerminator) { + if (uc == ptr) { // for(literal) (only "ever" would be legal if qmake was sane) putTok(tokPtr, TokForLoop); putHashStr(tokPtr, (ushort *)0, (uint)0); @@ -1061,8 +1111,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg defType = TokTestDef; deffunc: if (m_invert) { - parseError(fL1S("Unexpected operator in front of function definition.")); - bogusTest(tokPtr); + bogusTest(tokPtr, fL1S("Unexpected NOT operator in front of function definition.")); return; } flushScopes(tokPtr); @@ -1070,10 +1119,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg if (*uce == (TokLiteral|TokNewStr)) { uint nlen = uce[1]; if (uce[nlen + 2] == TokFuncTerminator) { - if (m_operator != NoOperator) { - putTok(tokPtr, (m_operator == AndOperator) ? TokAnd : TokOr); - m_operator = NoOperator; - } + putOperator(tokPtr); putTok(tokPtr, defType); putHashStr(tokPtr, uce + 2, nlen); enterScope(tokPtr, true, StCtrl); @@ -1086,14 +1132,12 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg } 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); + bogusTest(tokPtr, fL1S("return() requires zero or one argument.")); return; } } else { if (*uce != TokFuncTerminator) { - parseError(fL1S("Top-level return() requires zero arguments.")); - bogusTest(tokPtr); + bogusTest(tokPtr, fL1S("Top-level return() requires zero arguments.")); return; } } @@ -1106,19 +1150,16 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg defType = TokBreak; ctrlstm: if (*uce != TokFuncTerminator) { - parseError(fL1S("%1() requires zero arguments.").arg(m_tmp)); - bogusTest(tokPtr); + bogusTest(tokPtr, fL1S("%1() requires zero arguments.").arg(m_tmp)); return; } if (!(m_blockstack.top().nest & NestLoop)) { - parseError(fL1S("Unexpected %1().").arg(m_tmp)); - bogusTest(tokPtr); + bogusTest(tokPtr, fL1S("Unexpected %1().").arg(m_tmp)); return; } ctrlstm2: if (m_invert) { - parseError(fL1S("Unexpected NOT operator in front of %1().").arg(m_tmp)); - bogusTest(tokPtr); + bogusTest(tokPtr, fL1S("Unexpected NOT operator in front of %1().").arg(m_tmp)); return; } finalizeTest(tokPtr); @@ -1128,8 +1169,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg } else if (m_tmp == statics.stroption) { if (m_state != StNew || m_blockstack.top().braceLevel || m_blockstack.size() > 1 || m_invert || m_operator != NoOperator) { - parseError(fL1S("option() must appear outside any control structures.")); - bogusTest(tokPtr); + bogusTest(tokPtr, fL1S("option() must appear outside any control structures.")); return; } if (*uce == (TokLiteral|TokNewStr)) { @@ -1210,4 +1250,258 @@ void QMakeParser::message(int type, const QString &msg) const m_handler->message(type, msg, m_proFile->fileName(), m_lineNo); } +#ifdef PROPARSER_DEBUG + +#define BOUNDS_CHECK(need) \ + do { \ + int have = limit - offset; \ + if (have < (int)need) { \ + *outStr += fL1S("<out of bounds (need %1, got %2)>").arg(need).arg(have); \ + return false; \ + } \ + } while (0) + +static bool getRawUshort(const ushort *tokens, int limit, int &offset, ushort *outVal, QString *outStr) +{ + BOUNDS_CHECK(1); + uint val = tokens[offset++]; + *outVal = val; + return true; +} + +static bool getUshort(const ushort *tokens, int limit, int &offset, ushort *outVal, QString *outStr) +{ + *outStr += fL1S(" << H("); + if (!getRawUshort(tokens, limit, offset, outVal, outStr)) + return false; + *outStr += QString::number(*outVal) + QLatin1Char(')'); + return true; +} + +static bool getRawUint(const ushort *tokens, int limit, int &offset, uint *outVal, QString *outStr) +{ + BOUNDS_CHECK(2); + uint val = tokens[offset++]; + val |= (uint)tokens[offset++] << 16; + *outVal = val; + return true; +} + +static bool getUint(const ushort *tokens, int limit, int &offset, uint *outVal, QString *outStr) +{ + *outStr += fL1S(" << I("); + if (!getRawUint(tokens, limit, offset, outVal, outStr)) + return false; + *outStr += QString::number(*outVal) + QLatin1Char(')'); + return true; +} + +static bool getRawStr(const ushort *tokens, int limit, int &offset, int strLen, QString *outStr) +{ + BOUNDS_CHECK(strLen); + *outStr += fL1S("L\""); + bool attn = false; + for (int i = 0; i < strLen; i++) { + ushort val = tokens[offset++]; + switch (val) { + case '"': *outStr += fL1S("\\\""); break; + case '\n': *outStr += fL1S("\\n"); break; + case '\r': *outStr += fL1S("\\r"); break; + case '\t': *outStr += fL1S("\\t"); break; + case '\\': *outStr += fL1S("\\\\"); break; + default: + if (val < 32 || val > 126) { + *outStr += (val > 255 ? fL1S("\\u") : fL1S("\\x")) + QString::number(val, 16); + attn = true; + continue; + } + if (attn && isxdigit(val)) + *outStr += fL1S("\"\""); + *outStr += QChar(val); + break; + } + attn = false; + } + *outStr += QLatin1Char('"'); + return true; +} + +static bool getStr(const ushort *tokens, int limit, int &offset, QString *outStr) +{ + *outStr += fL1S(" << S("); + ushort len; + if (!getRawUshort(tokens, limit, offset, &len, outStr)) + return false; + if (!getRawStr(tokens, limit, offset, len, outStr)) + return false; + *outStr += QLatin1Char(')'); + return true; +} + +static bool getHashStr(const ushort *tokens, int limit, int &offset, QString *outStr) +{ + *outStr += fL1S(" << HS("); + uint hash; + if (!getRawUint(tokens, limit, offset, &hash, outStr)) + return false; + ushort len; + if (!getRawUshort(tokens, limit, offset, &len, outStr)) + return false; + const QChar *chars = (const QChar *)tokens + offset; + if (!getRawStr(tokens, limit, offset, len, outStr)) + return false; + uint realhash = ProString::hash(chars, len); + if (realhash != hash) + *outStr += fL1S(" /* Bad hash ") + QString::number(hash) + fL1S(" */"); + *outStr += QLatin1Char(')'); + return true; +} + +static bool getBlock(const ushort *tokens, int limit, int &offset, QString *outStr, int indent); + +static bool getSubBlock(const ushort *tokens, int limit, int &offset, QString *outStr, int indent, + const char *scope) +{ + *outStr += fL1S("\n /* %1 */ ").arg(offset, 5) + + QString(indent * 4, QLatin1Char(' ')) + + fL1S("/* ") + fL1S(scope) + fL1S(" */"); + uint len; + if (!getUint(tokens, limit, offset, &len, outStr)) + return false; + if (len) { + BOUNDS_CHECK(len); + int tmpOff = offset; + offset += len; + forever { + if (!getBlock(tokens, offset, tmpOff, outStr, indent + 1)) + break; // Error was already reported, try to continue + if (tmpOff == offset) + break; + *outStr += QLatin1Char('\n') + QString(20 + indent * 4, QLatin1Char(' ')) + + fL1S("/* Warning: Excess tokens follow. */"); + } + } + return true; +} + +static bool getBlock(const ushort *tokens, int limit, int &offset, QString *outStr, int indent) +{ + static const char * const tokNames[] = { + "TokTerminator", + "TokLine", + "TokAssign", "TokAppend", "TokAppendUnique", "TokRemove", "TokReplace", + "TokValueTerminator", + "TokLiteral", "TokHashLiteral", "TokVariable", "TokProperty", "TokEnvVar", + "TokFuncName", "TokArgSeparator", "TokFuncTerminator", + "TokCondition", "TokTestCall", + "TokReturn", "TokBreak", "TokNext", + "TokNot", "TokAnd", "TokOr", + "TokBranch", "TokForLoop", + "TokTestDef", "TokReplaceDef" + }; + + while (offset != limit) { + *outStr += fL1S("\n /* %1 */").arg(offset, 5) + + QString(indent * 4, QLatin1Char(' ')); + BOUNDS_CHECK(1); + ushort tok = tokens[offset++]; + ushort maskedTok = tok & TokMask; + if (maskedTok >= sizeof(tokNames)/sizeof(tokNames[0]) + || (tok & ~(TokNewStr | TokQuoted | TokMask))) { + *outStr += fL1S(" << {invalid token %1}").arg(tok); + return false; + } + *outStr += fL1S(" << H(") + fL1S(tokNames[maskedTok]); + if (tok & TokNewStr) + *outStr += fL1S(" | TokNewStr"); + if (tok & TokQuoted) + *outStr += fL1S(" | TokQuoted"); + *outStr += QLatin1Char(')'); + bool ok; + switch (maskedTok) { + case TokFuncTerminator: // Recursion, but not a sub-block + return true; + case TokArgSeparator: + case TokValueTerminator: // Not recursion + case TokTerminator: // Recursion, and limited by (sub-)block length + case TokCondition: + case TokReturn: + case TokBreak: + case TokNext: + case TokNot: + case TokAnd: + case TokOr: + ok = true; + break; + case TokTestCall: + ok = getBlock(tokens, limit, offset, outStr, indent + 1); + break; + case TokBranch: + ok = getSubBlock(tokens, limit, offset, outStr, indent, "then branch"); + if (ok) + ok = getSubBlock(tokens, limit, offset, outStr, indent, "else branch"); + break; + default: + switch (maskedTok) { + case TokAssign: + case TokAppend: + case TokAppendUnique: + case TokRemove: + case TokReplace: + // The parameter is the sizehint for the output. + // fallthrough + case TokLine: { + ushort dummy; + ok = getUshort(tokens, limit, offset, &dummy, outStr); + break; } + case TokLiteral: + case TokEnvVar: + ok = getStr(tokens, limit, offset, outStr); + break; + case TokHashLiteral: + case TokVariable: + case TokProperty: + ok = getHashStr(tokens, limit, offset, outStr); + break; + case TokFuncName: + ok = getHashStr(tokens, limit, offset, outStr); + if (ok) + ok = getBlock(tokens, limit, offset, outStr, indent + 1); + break; + case TokForLoop: + ok = getHashStr(tokens, limit, offset, outStr); + if (ok) + ok = getSubBlock(tokens, limit, offset, outStr, indent, "iterator"); + if (ok) + ok = getSubBlock(tokens, limit, offset, outStr, indent, "body"); + break; + case TokTestDef: + case TokReplaceDef: + ok = getHashStr(tokens, limit, offset, outStr); + if (ok) + ok = getSubBlock(tokens, limit, offset, outStr, indent, "body"); + break; + default: + Q_ASSERT(!"unhandled token"); + } + } + if (!ok) + return false; + } + return true; +} + +QString QMakeParser::formatProBlock(const QString &block) +{ + QString outStr; + outStr += fL1S("\n << TS("); + int offset = 0; + getBlock(reinterpret_cast<const ushort *>(block.constData()), block.length(), + offset, &outStr, 0); + outStr += QLatin1Char(')'); + return outStr; +} + +#endif // PROPARSER_DEBUG + QT_END_NAMESPACE diff --git a/qmake/library/qmakeparser.h b/qmake/library/qmakeparser.h index f8bbe905c3..dfea1ddfdf 100644 --- a/qmake/library/qmakeparser.h +++ b/qmake/library/qmakeparser.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -96,6 +96,10 @@ public: void discardFileFromCache(const QString &fileName); +#ifdef PROPARSER_DEBUG + static QString formatProBlock(const QString &block); +#endif + private: enum ScopeNesting { NestNone = 0, @@ -130,7 +134,7 @@ private: }; bool read(ProFile *pro, ParseFlags flags); - bool read(ProFile *pro, const QString &content, int line, SubGrammar grammar); + void read(ProFile *pro, const QString &content, int line, SubGrammar grammar); ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok); ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len); @@ -144,8 +148,12 @@ private: const ushort *cur, const QString &in); void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount); void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc); + void warnOperator(const char *msg); + bool failOperator(const char *msg); + bool acceptColon(const char *msg); + void putOperator(ushort *&tokPtr); void finalizeTest(ushort *&tokPtr); - void bogusTest(ushort *&tokPtr); + void bogusTest(ushort *&tokPtr, const QString &msg); void enterScope(ushort *&tokPtr, bool special, ScopeState state); void leaveScope(ushort *&tokPtr); void flushCond(ushort *&tokPtr); @@ -153,7 +161,10 @@ private: void message(int type, const QString &msg) const; void parseError(const QString &msg) const - { message(QMakeParserHandler::ParserError, msg); } + { + message(QMakeParserHandler::ParserError, msg); + m_proFile->setOk(false); + } void languageWarning(const QString &msg) const { message(QMakeParserHandler::ParserWarnLanguage, msg); } void deprecationWarning(const QString &msg) const @@ -168,7 +179,7 @@ private: int m_markLine; // Put marker for this line bool m_inError; // Current line had a parsing error; suppress followup error messages bool m_canElse; // Conditionals met on previous line, but no scope was opened - bool m_invert; // Pending conditional is negated + int m_invert; // Pending conditional is negated enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed QString m_tmp; // Temporary for efficient toQString diff --git a/qmake/library/qmakevfs.cpp b/qmake/library/qmakevfs.cpp index 125d074ce3..613e4e90d7 100644 --- a/qmake/library/qmakevfs.cpp +++ b/qmake/library/qmakevfs.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ diff --git a/qmake/library/qmakevfs.h b/qmake/library/qmakevfs.h index 80e0eec07b..8eeae15dcc 100644 --- a/qmake/library/qmakevfs.h +++ b/qmake/library/qmakevfs.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the qmake application of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ |