2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
2010-03-05 11:25:49 +01:00
|
|
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-06-17 00:01:27 +10:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Commercial Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Nokia.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** If you are unsure which license is appropriate for your use, please
|
2009-08-14 09:30:56 +02:00
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2008-12-02 12:57:59 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "profileevaluator.h"
|
|
|
|
|
#include "proitems.h"
|
2010-01-22 12:26:14 +01:00
|
|
|
#include "ioutils.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
#include <QtCore/QByteArray>
|
2008-12-12 16:30:31 +01:00
|
|
|
#include <QtCore/QDateTime>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <QtCore/QDebug>
|
|
|
|
|
#include <QtCore/QDir>
|
|
|
|
|
#include <QtCore/QFile>
|
|
|
|
|
#include <QtCore/QFileInfo>
|
|
|
|
|
#include <QtCore/QList>
|
|
|
|
|
#include <QtCore/QRegExp>
|
|
|
|
|
#include <QtCore/QSet>
|
|
|
|
|
#include <QtCore/QStack>
|
|
|
|
|
#include <QtCore/QString>
|
|
|
|
|
#include <QtCore/QStringList>
|
|
|
|
|
#include <QtCore/QTextStream>
|
2010-02-26 12:53:30 +01:00
|
|
|
#ifdef PROPARSER_THREAD_SAFE
|
|
|
|
|
# include <QtCore/QThreadPool>
|
|
|
|
|
#endif
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-12 16:30:31 +01:00
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/utsname.h>
|
2009-06-03 20:45:49 +02:00
|
|
|
#else
|
2008-12-12 16:30:31 +01:00
|
|
|
#include <Windows.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
|
#define QT_POPEN _popen
|
2009-06-04 15:18:14 +02:00
|
|
|
#define QT_PCLOSE _pclose
|
2008-12-02 12:01:29 +01:00
|
|
|
#else
|
|
|
|
|
#define QT_POPEN popen
|
2009-06-04 15:18:14 +02:00
|
|
|
#define QT_PCLOSE pclose
|
2008-12-02 12:01:29 +01:00
|
|
|
#endif
|
|
|
|
|
|
2010-01-22 12:26:14 +01:00
|
|
|
using namespace ProFileEvaluatorInternal;
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
|
2009-08-10 17:27:07 +02:00
|
|
|
static void refFunctions(QHash<QString, ProBlock *> *defs)
|
|
|
|
|
{
|
|
|
|
|
foreach (ProBlock *itm, *defs)
|
|
|
|
|
itm->ref();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void clearFunctions(QHash<QString, ProBlock *> *defs)
|
|
|
|
|
{
|
|
|
|
|
foreach (ProBlock *itm, *defs)
|
|
|
|
|
itm->deref();
|
|
|
|
|
defs->clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void clearFunctions(ProFileEvaluator::FunctionDefs *defs)
|
|
|
|
|
{
|
|
|
|
|
clearFunctions(&defs->replaceFunctions);
|
|
|
|
|
clearFunctions(&defs->testFunctions);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
|
2008-12-12 16:30:31 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
2009-12-07 22:58:47 +01:00
|
|
|
// ProFileCache
|
2008-12-12 16:30:31 +01:00
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2009-12-07 22:58:47 +01:00
|
|
|
ProFileCache::~ProFileCache()
|
|
|
|
|
{
|
2010-02-26 12:53:30 +01:00
|
|
|
foreach (const Entry &ent, parsed_files)
|
|
|
|
|
if (ent.pro)
|
|
|
|
|
ent.pro->deref();
|
2009-12-07 22:58:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileCache::discardFile(const QString &fileName)
|
|
|
|
|
{
|
2010-02-26 12:53:30 +01:00
|
|
|
#ifdef PROPARSER_THREAD_SAFE
|
|
|
|
|
QMutexLocker lck(&mutex);
|
|
|
|
|
#endif
|
|
|
|
|
QHash<QString, Entry>::Iterator it = parsed_files.find(fileName);
|
2009-12-07 22:58:47 +01:00
|
|
|
if (it != parsed_files.end()) {
|
2010-02-26 12:53:30 +01:00
|
|
|
if (it->pro)
|
|
|
|
|
it->pro->deref();
|
2009-12-07 22:58:47 +01:00
|
|
|
parsed_files.erase(it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileCache::discardFiles(const QString &prefix)
|
|
|
|
|
{
|
2010-02-26 12:53:30 +01:00
|
|
|
#ifdef PROPARSER_THREAD_SAFE
|
|
|
|
|
QMutexLocker lck(&mutex);
|
|
|
|
|
#endif
|
|
|
|
|
QHash<QString, Entry>::Iterator
|
2009-12-07 22:58:47 +01:00
|
|
|
it = parsed_files.begin(),
|
|
|
|
|
end = parsed_files.end();
|
|
|
|
|
while (it != end)
|
|
|
|
|
if (it.key().startsWith(prefix)) {
|
2010-02-26 12:53:30 +01:00
|
|
|
if (it->pro)
|
|
|
|
|
it->pro->deref();
|
2009-12-07 22:58:47 +01:00
|
|
|
it = parsed_files.erase(it);
|
|
|
|
|
} else {
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
2009-12-07 20:32:36 +01:00
|
|
|
// ProFileOption
|
2009-12-07 22:58:47 +01:00
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2009-12-07 20:32:36 +01:00
|
|
|
ProFileOption::ProFileOption()
|
2009-07-23 18:36:59 +02:00
|
|
|
{
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
dirlist_sep = QLatin1Char(';');
|
|
|
|
|
dir_sep = QLatin1Char('\\');
|
|
|
|
|
#else
|
|
|
|
|
dirlist_sep = QLatin1Char(':');
|
|
|
|
|
dir_sep = QLatin1Char('/');
|
|
|
|
|
#endif
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").data());
|
2009-07-23 18:36:59 +02:00
|
|
|
|
2008-12-12 16:30:31 +01:00
|
|
|
#if defined(Q_OS_WIN32)
|
2009-07-23 18:36:59 +02:00
|
|
|
target_mode = TARG_WIN_MODE;
|
2009-07-23 17:04:50 +02:00
|
|
|
#elif defined(Q_OS_MAC)
|
2009-07-23 18:36:59 +02:00
|
|
|
target_mode = TARG_MACX_MODE;
|
2009-07-23 17:04:50 +02:00
|
|
|
#elif defined(Q_OS_QNX6)
|
2009-07-23 18:36:59 +02:00
|
|
|
target_mode = TARG_QNX6_MODE;
|
2008-12-12 16:30:31 +01:00
|
|
|
#else
|
2009-07-23 18:36:59 +02:00
|
|
|
target_mode = TARG_UNIX_MODE;
|
2008-12-12 16:30:31 +01:00
|
|
|
#endif
|
|
|
|
|
|
2009-12-07 22:58:47 +01:00
|
|
|
cache = 0;
|
2010-06-04 17:08:27 +02:00
|
|
|
|
|
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
|
|
|
|
base_inProgress = false;
|
|
|
|
|
#endif
|
2009-07-23 18:36:59 +02:00
|
|
|
}
|
|
|
|
|
|
2009-12-07 20:32:36 +01:00
|
|
|
ProFileOption::~ProFileOption()
|
2009-08-10 17:27:07 +02:00
|
|
|
{
|
|
|
|
|
clearFunctions(&base_functions);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// ProFileEvaluator::Private
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-02-02 21:00:09 +01:00
|
|
|
class ProFileEvaluator::Private
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
public:
|
2010-02-08 16:47:25 +01:00
|
|
|
static void initStatics();
|
2009-12-07 20:32:36 +01:00
|
|
|
Private(ProFileEvaluator *q_, ProFileOption *option);
|
2009-08-10 17:27:07 +02:00
|
|
|
~Private();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-12 18:10:42 +01:00
|
|
|
ProFileEvaluator *q;
|
|
|
|
|
int m_lineNo; // Error reporting
|
|
|
|
|
bool m_verbose;
|
|
|
|
|
|
|
|
|
|
/////////////// Reading pro file
|
|
|
|
|
|
2010-02-03 16:50:11 +01:00
|
|
|
struct BlockCursor {
|
|
|
|
|
BlockCursor() : cursor(0) {}
|
|
|
|
|
BlockCursor(ProBlock *blk) : block(blk), cursor(blk->itemsRef()) {}
|
|
|
|
|
~BlockCursor() { if (cursor) *cursor = 0; }
|
|
|
|
|
void set(ProBlock *blk) { if (cursor) *cursor = 0; block = blk; cursor = blk->itemsRef(); }
|
|
|
|
|
void reset() { if (cursor) { *cursor = 0; cursor = 0; } }
|
|
|
|
|
void append(ProItem *item) { *cursor = item; cursor = item->nextRef(); }
|
|
|
|
|
bool isValid() const { return cursor != 0; }
|
|
|
|
|
ProBlock *block;
|
|
|
|
|
ProItem **cursor;
|
|
|
|
|
};
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
bool read(ProFile *pro);
|
2010-04-13 21:00:23 +02:00
|
|
|
bool read(ProFile *pro, const QString &content);
|
2009-10-02 17:37:02 +02:00
|
|
|
bool read(ProBlock *pro, const QString &content);
|
2010-01-18 22:57:45 +01:00
|
|
|
bool readInternal(ProBlock *pro, const QString &content, ushort *buf);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-03 16:50:11 +01:00
|
|
|
BlockCursor ¤tBlock();
|
2010-01-18 22:57:45 +01:00
|
|
|
void updateItem(ushort *uc, ushort *ptr);
|
|
|
|
|
ProVariable *startVariable(ushort *uc, ushort *ptr);
|
|
|
|
|
void finalizeVariable(ProVariable *var, ushort *uc, ushort *ptr);
|
2008-12-02 12:01:29 +01:00
|
|
|
void insertOperator(const char op);
|
|
|
|
|
void enterScope(bool multiLine);
|
|
|
|
|
void leaveScope();
|
|
|
|
|
void finalizeBlock();
|
|
|
|
|
|
2010-02-03 16:50:11 +01:00
|
|
|
QStack<BlockCursor> m_blockstack;
|
|
|
|
|
BlockCursor m_block;
|
2008-12-12 18:10:42 +01:00
|
|
|
|
|
|
|
|
/////////////// Evaluating pro file contents
|
|
|
|
|
|
2010-02-02 21:00:09 +01:00
|
|
|
ProItem::ProItemReturn visitProFile(ProFile *pro);
|
|
|
|
|
ProItem::ProItemReturn visitProBlock(ProBlock *block);
|
|
|
|
|
ProItem::ProItemReturn visitProItem(ProItem *item);
|
2009-05-19 19:00:06 +02:00
|
|
|
ProItem::ProItemReturn visitProLoopIteration();
|
|
|
|
|
void visitProLoopCleanup();
|
2010-01-14 12:34:46 +01:00
|
|
|
void visitProVariable(ProVariable *variable);
|
2009-05-18 17:46:30 +02:00
|
|
|
ProItem::ProItemReturn visitProFunction(ProFunction *function);
|
2009-05-18 17:25:41 +02:00
|
|
|
void visitProOperator(ProOperator *oper);
|
|
|
|
|
void visitProCondition(ProCondition *condition);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-11 16:33:16 +01:00
|
|
|
static inline QString map(const QString &var);
|
2010-02-09 20:38:21 +01:00
|
|
|
QHash<QString, QStringList> *findValues(const QString &variableName,
|
|
|
|
|
QHash<QString, QStringList>::Iterator *it);
|
|
|
|
|
QStringList &valuesRef(const QString &variableName);
|
|
|
|
|
QStringList valuesDirect(const QString &variableName) const;
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList values(const QString &variableName) const;
|
2009-08-04 15:56:26 +02:00
|
|
|
QString propertyValue(const QString &val, bool complain = true) const;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-14 17:43:02 +01:00
|
|
|
static QStringList split_value_list(const QString &vals);
|
2008-12-02 12:01:29 +01:00
|
|
|
bool isActiveConfig(const QString &config, bool regex = false);
|
2010-01-19 12:31:39 +01:00
|
|
|
QStringList expandVariableReferences(const QString &value, bool do_semicolon = false,
|
|
|
|
|
int *pos = 0);
|
2009-05-19 19:00:06 +02:00
|
|
|
void doVariableReplace(QString *str);
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList evaluateExpandFunction(const QString &function, const QString &arguments);
|
|
|
|
|
QString format(const char *format) const;
|
2009-08-12 13:00:21 +02:00
|
|
|
void logMessage(const QString &msg) const;
|
|
|
|
|
void errorMessage(const QString &msg) const;
|
|
|
|
|
void fileMessage(const QString &msg) const;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
QString currentFileName() const;
|
2008-12-19 21:19:38 +01:00
|
|
|
QString currentDirectory() const;
|
2008-12-02 12:01:29 +01:00
|
|
|
ProFile *currentProFile() const;
|
2010-01-22 12:26:14 +01:00
|
|
|
QString resolvePath(const QString &fileName) const
|
|
|
|
|
{ return IoUtils::resolvePath(currentDirectory(), fileName); }
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-05-18 17:46:30 +02:00
|
|
|
ProItem::ProItemReturn evaluateConditionalFunction(const QString &function, const QString &arguments);
|
2009-12-07 22:58:47 +01:00
|
|
|
ProFile *parsedProFile(const QString &fileName, bool cache,
|
|
|
|
|
const QString &contents = QString());
|
2010-06-07 21:25:11 +02:00
|
|
|
bool evaluateFileDirect(const QString &fileName, ProFileEvaluator::EvalFileType type);
|
2009-05-12 17:15:54 +02:00
|
|
|
bool evaluateFile(const QString &fileName);
|
2009-08-10 17:27:07 +02:00
|
|
|
bool evaluateFeatureFile(const QString &fileName,
|
|
|
|
|
QHash<QString, QStringList> *values = 0, FunctionDefs *defs = 0);
|
|
|
|
|
bool evaluateFileInto(const QString &fileName,
|
|
|
|
|
QHash<QString, QStringList> *values, FunctionDefs *defs);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-05-18 17:46:30 +02:00
|
|
|
static inline ProItem::ProItemReturn returnBool(bool b)
|
|
|
|
|
{ return b ? ProItem::ReturnTrue : ProItem::ReturnFalse; }
|
|
|
|
|
|
2009-08-14 17:36:07 +02:00
|
|
|
QList<QStringList> prepareFunctionArgs(const QString &arguments);
|
|
|
|
|
QStringList evaluateFunction(ProBlock *funcPtr, const QList<QStringList> &argumentsList, bool *ok);
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2009-07-23 18:36:59 +02:00
|
|
|
QStringList qmakeMkspecPaths() const;
|
|
|
|
|
QStringList qmakeFeaturePaths() const;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-05-13 12:32:24 +02:00
|
|
|
struct State {
|
2009-05-14 14:35:37 +02:00
|
|
|
bool condition;
|
|
|
|
|
bool prevCondition;
|
2009-05-13 12:32:24 +02:00
|
|
|
} m_sts;
|
|
|
|
|
bool m_invertNext; // Short-lived, so not in State
|
2009-08-14 14:36:34 +02:00
|
|
|
bool m_hadCondition; // Nested calls set it on return, so no need for it to be in State
|
2008-12-12 18:10:42 +01:00
|
|
|
int m_skipLevel;
|
|
|
|
|
bool m_cumulative;
|
2008-12-02 12:01:29 +01:00
|
|
|
QStack<ProFile*> m_profileStack; // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri'
|
2009-05-19 19:00:06 +02:00
|
|
|
struct ProLoop {
|
|
|
|
|
QString variable;
|
|
|
|
|
QStringList oldVarVal;
|
|
|
|
|
QStringList list;
|
|
|
|
|
int index;
|
|
|
|
|
bool infinite;
|
|
|
|
|
};
|
|
|
|
|
QStack<ProLoop> m_loopStack;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-12 16:30:31 +01:00
|
|
|
QString m_outputDir;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-08 16:51:50 +01:00
|
|
|
int m_listCount;
|
2009-05-18 17:46:30 +02:00
|
|
|
bool m_definingTest;
|
|
|
|
|
QString m_definingFunc;
|
2009-08-10 17:27:07 +02:00
|
|
|
FunctionDefs m_functionDefs;
|
2009-05-18 17:46:30 +02:00
|
|
|
QStringList m_returnValue;
|
2010-02-09 20:38:21 +01:00
|
|
|
QStack<QHash<QString, QStringList> > m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii.
|
|
|
|
|
QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2009-03-19 15:04:43 +01:00
|
|
|
QStringList m_addUserConfigCmdArgs;
|
|
|
|
|
QStringList m_removeUserConfigCmdArgs;
|
2009-05-25 16:43:50 +02:00
|
|
|
bool m_parsePreAndPostFiles;
|
2009-07-23 18:36:59 +02:00
|
|
|
|
2009-12-07 20:32:36 +01:00
|
|
|
ProFileOption *m_option;
|
2010-02-08 16:47:25 +01:00
|
|
|
|
|
|
|
|
enum ExpandFunc {
|
|
|
|
|
E_MEMBER=1, E_FIRST, E_LAST, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
|
|
|
|
|
E_SPRINTF, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
|
|
|
|
|
E_FIND, E_SYSTEM, E_UNIQUE, E_QUOTE, E_ESCAPE_EXPAND,
|
|
|
|
|
E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE,
|
|
|
|
|
E_REPLACE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum TestFunc {
|
|
|
|
|
T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS,
|
|
|
|
|
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_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF,
|
|
|
|
|
T_FOR, T_DEFINE_TEST, T_DEFINE_REPLACE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum VarName {
|
|
|
|
|
V_LITERAL_DOLLAR, V_LITERAL_HASH, V_LITERAL_WHITESPACE,
|
|
|
|
|
V_DIRLIST_SEPARATOR, V_DIR_SEPARATOR,
|
|
|
|
|
V_OUT_PWD, V_PWD, V_IN_PWD,
|
|
|
|
|
V__FILE_, V__LINE_, V__PRO_FILE_, V__PRO_FILE_PWD_,
|
|
|
|
|
V_QMAKE_HOST_arch, V_QMAKE_HOST_name, V_QMAKE_HOST_os,
|
|
|
|
|
V_QMAKE_HOST_version, V_QMAKE_HOST_version_string,
|
|
|
|
|
V__DATE_, V__QMAKE_CACHE_
|
|
|
|
|
};
|
2008-12-02 12:01:29 +01:00
|
|
|
};
|
|
|
|
|
|
2009-06-04 09:49:23 +02:00
|
|
|
#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
|
2009-05-13 12:32:24 +02:00
|
|
|
Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::State, Q_PRIMITIVE_TYPE);
|
2009-05-19 19:00:06 +02:00
|
|
|
Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::ProLoop, Q_MOVABLE_TYPE);
|
2010-02-08 16:49:24 +01:00
|
|
|
Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::BlockCursor, Q_MOVABLE_TYPE);
|
2009-06-04 09:49:23 +02:00
|
|
|
#endif
|
2009-05-13 12:32:24 +02:00
|
|
|
|
2010-02-08 16:47:25 +01:00
|
|
|
static struct {
|
|
|
|
|
QString field_sep;
|
|
|
|
|
QString deppath;
|
|
|
|
|
QString incpath;
|
2010-02-08 17:15:44 +01:00
|
|
|
QString strelse;
|
|
|
|
|
QString strtrue;
|
|
|
|
|
QString strfalse;
|
|
|
|
|
QString strunix;
|
|
|
|
|
QString strmacx;
|
|
|
|
|
QString strqnx6;
|
|
|
|
|
QString strmac9;
|
|
|
|
|
QString strmac;
|
|
|
|
|
QString strwin32;
|
|
|
|
|
QString strCONFIG;
|
|
|
|
|
QString strARGS;
|
|
|
|
|
QString strDot;
|
|
|
|
|
QString strDotDot;
|
|
|
|
|
QString strever;
|
|
|
|
|
QString strforever;
|
|
|
|
|
QString strTEMPLATE;
|
|
|
|
|
QString strQMAKE_DIR_SEP;
|
2010-02-08 16:47:25 +01:00
|
|
|
QHash<QString, int> expands;
|
|
|
|
|
QHash<QString, int> functions;
|
|
|
|
|
QHash<QString, int> varList;
|
2010-02-11 16:33:16 +01:00
|
|
|
QHash<QString, QString> varMap;
|
2010-02-08 17:15:44 +01:00
|
|
|
QRegExp reg_variableName;
|
2010-02-09 20:38:21 +01:00
|
|
|
QStringList fakeValue;
|
2010-02-08 16:47:25 +01:00
|
|
|
} statics;
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::initStatics()
|
|
|
|
|
{
|
|
|
|
|
if (!statics.field_sep.isNull())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
statics.field_sep = QLatin1String(" ");
|
|
|
|
|
statics.deppath = QLatin1String("DEPENDPATH");
|
|
|
|
|
statics.incpath = QLatin1String("INCLUDEPATH");
|
2010-02-08 17:15:44 +01:00
|
|
|
statics.strelse = QLatin1String("else");
|
|
|
|
|
statics.strtrue = QLatin1String("true");
|
|
|
|
|
statics.strfalse = QLatin1String("false");
|
|
|
|
|
statics.strunix = QLatin1String("unix");
|
|
|
|
|
statics.strmacx = QLatin1String("macx");
|
|
|
|
|
statics.strqnx6 = QLatin1String("qnx6");
|
|
|
|
|
statics.strmac9 = QLatin1String("mac9");
|
|
|
|
|
statics.strmac = QLatin1String("mac");
|
|
|
|
|
statics.strwin32 = QLatin1String("win32");
|
|
|
|
|
statics.strCONFIG = QLatin1String("CONFIG");
|
|
|
|
|
statics.strARGS = QLatin1String("ARGS");
|
|
|
|
|
statics.strDot = QLatin1String(".");
|
|
|
|
|
statics.strDotDot = QLatin1String("..");
|
|
|
|
|
statics.strever = QLatin1String("ever");
|
|
|
|
|
statics.strforever = QLatin1String("forever");
|
|
|
|
|
statics.strTEMPLATE = QLatin1String("TEMPLATE");
|
|
|
|
|
statics.strQMAKE_DIR_SEP = QLatin1String("QMAKE_DIR_SEP");
|
|
|
|
|
|
|
|
|
|
statics.reg_variableName.setPattern(QLatin1String("\\$\\(.*\\)"));
|
|
|
|
|
statics.reg_variableName.setMinimal(true);
|
2010-02-08 16:47:25 +01:00
|
|
|
|
2010-02-09 20:38:21 +01:00
|
|
|
statics.fakeValue.detach(); // It has to have a unique begin() value
|
|
|
|
|
|
2010-02-08 16:47:25 +01:00
|
|
|
static const struct {
|
|
|
|
|
const char * const name;
|
|
|
|
|
const ExpandFunc func;
|
|
|
|
|
} expandInits[] = {
|
|
|
|
|
{ "member", E_MEMBER },
|
|
|
|
|
{ "first", E_FIRST },
|
|
|
|
|
{ "last", E_LAST },
|
|
|
|
|
{ "cat", E_CAT },
|
|
|
|
|
{ "fromfile", E_FROMFILE },
|
|
|
|
|
{ "eval", E_EVAL },
|
|
|
|
|
{ "list", E_LIST },
|
|
|
|
|
{ "sprintf", E_SPRINTF },
|
|
|
|
|
{ "join", E_JOIN },
|
|
|
|
|
{ "split", E_SPLIT },
|
|
|
|
|
{ "basename", E_BASENAME },
|
|
|
|
|
{ "dirname", E_DIRNAME },
|
|
|
|
|
{ "section", E_SECTION },
|
|
|
|
|
{ "find", E_FIND },
|
|
|
|
|
{ "system", E_SYSTEM },
|
|
|
|
|
{ "unique", E_UNIQUE },
|
|
|
|
|
{ "quote", E_QUOTE },
|
|
|
|
|
{ "escape_expand", E_ESCAPE_EXPAND },
|
|
|
|
|
{ "upper", E_UPPER },
|
|
|
|
|
{ "lower", E_LOWER },
|
|
|
|
|
{ "re_escape", E_RE_ESCAPE },
|
|
|
|
|
{ "files", E_FILES },
|
|
|
|
|
{ "prompt", E_PROMPT }, // interactive, so cannot be implemented
|
|
|
|
|
{ "replace", E_REPLACE }
|
|
|
|
|
};
|
|
|
|
|
for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i)
|
|
|
|
|
statics.expands.insert(QLatin1String(expandInits[i].name), expandInits[i].func);
|
|
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char * const name;
|
|
|
|
|
const TestFunc func;
|
|
|
|
|
} testInits[] = {
|
|
|
|
|
{ "requires", T_REQUIRES },
|
|
|
|
|
{ "greaterThan", T_GREATERTHAN },
|
|
|
|
|
{ "lessThan", T_LESSTHAN },
|
|
|
|
|
{ "equals", T_EQUALS },
|
|
|
|
|
{ "isEqual", T_EQUALS },
|
|
|
|
|
{ "exists", T_EXISTS },
|
|
|
|
|
{ "export", T_EXPORT },
|
|
|
|
|
{ "clear", T_CLEAR },
|
|
|
|
|
{ "unset", T_UNSET },
|
|
|
|
|
{ "eval", T_EVAL },
|
|
|
|
|
{ "CONFIG", T_CONFIG },
|
|
|
|
|
{ "if", T_IF },
|
|
|
|
|
{ "isActiveConfig", T_CONFIG },
|
|
|
|
|
{ "system", T_SYSTEM },
|
|
|
|
|
{ "return", T_RETURN },
|
|
|
|
|
{ "break", T_BREAK },
|
|
|
|
|
{ "next", T_NEXT },
|
|
|
|
|
{ "defined", T_DEFINED },
|
|
|
|
|
{ "contains", T_CONTAINS },
|
|
|
|
|
{ "infile", T_INFILE },
|
|
|
|
|
{ "count", T_COUNT },
|
|
|
|
|
{ "isEmpty", T_ISEMPTY },
|
|
|
|
|
{ "load", T_LOAD },
|
|
|
|
|
{ "include", T_INCLUDE },
|
|
|
|
|
{ "debug", T_DEBUG },
|
|
|
|
|
{ "message", T_MESSAGE },
|
|
|
|
|
{ "warning", T_MESSAGE },
|
|
|
|
|
{ "error", T_MESSAGE },
|
|
|
|
|
{ "for", T_FOR },
|
|
|
|
|
{ "defineTest", T_DEFINE_TEST },
|
|
|
|
|
{ "defineReplace", T_DEFINE_REPLACE }
|
|
|
|
|
};
|
|
|
|
|
for (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i)
|
|
|
|
|
statics.functions.insert(QLatin1String(testInits[i].name), testInits[i].func);
|
|
|
|
|
|
|
|
|
|
static const char * const names[] = {
|
|
|
|
|
"LITERAL_DOLLAR", "LITERAL_HASH", "LITERAL_WHITESPACE",
|
|
|
|
|
"DIRLIST_SEPARATOR", "DIR_SEPARATOR",
|
|
|
|
|
"OUT_PWD", "PWD", "IN_PWD",
|
|
|
|
|
"_FILE_", "_LINE_", "_PRO_FILE_", "_PRO_FILE_PWD_",
|
|
|
|
|
"QMAKE_HOST.arch", "QMAKE_HOST.name", "QMAKE_HOST.os",
|
|
|
|
|
"QMAKE_HOST.version", "QMAKE_HOST.version_string",
|
|
|
|
|
"_DATE_", "_QMAKE_CACHE_"
|
|
|
|
|
};
|
|
|
|
|
for (unsigned i = 0; i < sizeof(names)/sizeof(names[0]); ++i)
|
|
|
|
|
statics.varList.insert(QLatin1String(names[i]), i);
|
2010-02-11 16:33:16 +01:00
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char * const oldname, * const newname;
|
|
|
|
|
} mapInits[] = {
|
|
|
|
|
{ "INTERFACES", "FORMS" },
|
|
|
|
|
{ "QMAKE_POST_BUILD", "QMAKE_POST_LINK" },
|
|
|
|
|
{ "TARGETDEPS", "POST_TARGETDEPS" },
|
|
|
|
|
{ "LIBPATH", "QMAKE_LIBDIR" },
|
|
|
|
|
{ "QMAKE_EXT_MOC", "QMAKE_EXT_CPP_MOC" },
|
|
|
|
|
{ "QMAKE_MOD_MOC", "QMAKE_H_MOD_MOC" },
|
|
|
|
|
{ "QMAKE_LFLAGS_SHAPP", "QMAKE_LFLAGS_APP" },
|
|
|
|
|
{ "PRECOMPH", "PRECOMPILED_HEADER" },
|
|
|
|
|
{ "PRECOMPCPP", "PRECOMPILED_SOURCE" },
|
|
|
|
|
{ "INCPATH", "INCLUDEPATH" },
|
|
|
|
|
{ "QMAKE_EXTRA_WIN_COMPILERS", "QMAKE_EXTRA_COMPILERS" },
|
|
|
|
|
{ "QMAKE_EXTRA_UNIX_COMPILERS", "QMAKE_EXTRA_COMPILERS" },
|
|
|
|
|
{ "QMAKE_EXTRA_WIN_TARGETS", "QMAKE_EXTRA_TARGETS" },
|
|
|
|
|
{ "QMAKE_EXTRA_UNIX_TARGETS", "QMAKE_EXTRA_TARGETS" },
|
|
|
|
|
{ "QMAKE_EXTRA_UNIX_INCLUDES", "QMAKE_EXTRA_INCLUDES" },
|
|
|
|
|
{ "QMAKE_EXTRA_UNIX_VARIABLES", "QMAKE_EXTRA_VARIABLES" },
|
|
|
|
|
{ "QMAKE_RPATH", "QMAKE_LFLAGS_RPATH" },
|
|
|
|
|
{ "QMAKE_FRAMEWORKDIR", "QMAKE_FRAMEWORKPATH" },
|
|
|
|
|
{ "QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS" }
|
|
|
|
|
};
|
|
|
|
|
for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i)
|
|
|
|
|
statics.varMap.insert(QLatin1String(mapInits[i].oldname),
|
|
|
|
|
QLatin1String(mapInits[i].newname));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ProFileEvaluator::Private::map(const QString &var)
|
|
|
|
|
{
|
|
|
|
|
return statics.varMap.value(var, var);
|
2010-02-08 16:47:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-12-07 20:32:36 +01:00
|
|
|
ProFileEvaluator::Private::Private(ProFileEvaluator *q_, ProFileOption *option)
|
2009-07-23 18:36:59 +02:00
|
|
|
: q(q_), m_option(option)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-02-08 16:47:25 +01:00
|
|
|
// So that single-threaded apps don't have to call initialize() for now.
|
|
|
|
|
initStatics();
|
|
|
|
|
|
2009-04-02 19:38:19 +02:00
|
|
|
// Configuration, more or less
|
2008-12-02 12:01:29 +01:00
|
|
|
m_verbose = true;
|
2008-12-12 18:10:42 +01:00
|
|
|
m_cumulative = true;
|
2009-05-18 17:46:30 +02:00
|
|
|
m_parsePreAndPostFiles = true;
|
2009-04-02 19:38:19 +02:00
|
|
|
|
|
|
|
|
// Evaluator state
|
2009-05-14 14:35:37 +02:00
|
|
|
m_sts.condition = false;
|
|
|
|
|
m_sts.prevCondition = false;
|
2008-12-12 18:10:42 +01:00
|
|
|
m_invertNext = false;
|
|
|
|
|
m_skipLevel = 0;
|
2009-05-18 17:46:30 +02:00
|
|
|
m_definingFunc.clear();
|
2010-02-08 16:51:50 +01:00
|
|
|
m_listCount = 0;
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.push(QHash<QString, QStringList>());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-08-10 17:27:07 +02:00
|
|
|
ProFileEvaluator::Private::~Private()
|
|
|
|
|
{
|
|
|
|
|
clearFunctions(&m_functionDefs);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
////////// Parser ///////////
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
bool ProFileEvaluator::Private::read(ProFile *pro)
|
|
|
|
|
{
|
|
|
|
|
QFile file(pro->fileName());
|
2010-01-14 20:28:04 +01:00
|
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(pro->fileName()))
|
|
|
|
|
errorMessage(format("%1 not readable.").arg(pro->fileName()));
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
QString content(QString::fromLocal8Bit(file.readAll()));
|
2010-01-14 20:28:04 +01:00
|
|
|
file.close();
|
2009-10-02 17:37:02 +02:00
|
|
|
m_lineNo = 1;
|
2010-04-13 21:00:23 +02:00
|
|
|
m_profileStack.push(pro);
|
|
|
|
|
bool ret = readInternal(pro, content, (ushort*)content.data());
|
|
|
|
|
m_profileStack.pop();
|
|
|
|
|
return ret;
|
2009-07-07 13:13:12 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-13 21:00:23 +02:00
|
|
|
bool ProFileEvaluator::Private::read(ProFile *pro, const QString &content)
|
2009-07-07 13:13:12 +02:00
|
|
|
{
|
2010-01-18 22:57:45 +01:00
|
|
|
QString buf;
|
|
|
|
|
buf.reserve(content.size());
|
2009-10-02 17:37:02 +02:00
|
|
|
m_lineNo = 1;
|
2010-04-13 21:00:23 +02:00
|
|
|
m_profileStack.push(pro);
|
|
|
|
|
bool ret = readInternal(pro, content, (ushort*)buf.data());
|
|
|
|
|
m_profileStack.pop();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProFileEvaluator::Private::read(ProBlock *pro, const QString &content)
|
|
|
|
|
{
|
|
|
|
|
QString buf;
|
|
|
|
|
buf.reserve(content.size());
|
|
|
|
|
m_lineNo = 0;
|
2010-01-18 22:57:45 +01:00
|
|
|
return readInternal(pro, content, (ushort*)buf.data());
|
2009-07-07 13:13:12 +02:00
|
|
|
}
|
|
|
|
|
|
2010-01-18 22:57:45 +01:00
|
|
|
// We know that the buffer cannot grow larger than the input string,
|
|
|
|
|
// and the read() functions rely on it.
|
|
|
|
|
bool ProFileEvaluator::Private::readInternal(ProBlock *pro, const QString &in, ushort *buf)
|
2009-07-07 13:13:12 +02:00
|
|
|
{
|
2009-04-02 19:38:19 +02:00
|
|
|
// Parser state
|
2010-02-03 16:50:11 +01:00
|
|
|
m_blockstack.push(BlockCursor(pro));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-14 20:28:04 +01:00
|
|
|
// We rely on QStrings being null-terminated, so don't maintain a global end pointer.
|
|
|
|
|
const ushort *cur = (const ushort *)in.unicode();
|
2009-08-07 19:17:44 +02:00
|
|
|
freshLine:
|
2010-01-14 12:34:46 +01:00
|
|
|
ProVariable *currAssignment = 0;
|
2010-01-18 22:57:45 +01:00
|
|
|
ushort *ptr = buf;
|
2009-07-16 18:11:09 +02:00
|
|
|
int parens = 0;
|
2009-08-07 19:17:44 +02:00
|
|
|
bool inError = false;
|
|
|
|
|
bool putSpace = false;
|
|
|
|
|
ushort quote = 0;
|
2010-01-14 20:28:04 +01:00
|
|
|
forever {
|
2010-01-18 22:57:45 +01:00
|
|
|
ushort c;
|
2009-08-07 19:17:44 +02:00
|
|
|
|
|
|
|
|
// First, skip leading whitespace
|
2010-01-14 20:28:04 +01:00
|
|
|
for (;; ++cur) {
|
|
|
|
|
c = *cur;
|
|
|
|
|
if (c == '\n' || !c) { // Entirely empty line (sans whitespace)
|
2010-01-14 12:34:46 +01:00
|
|
|
if (currAssignment) {
|
2010-01-18 22:57:45 +01:00
|
|
|
finalizeVariable(currAssignment, buf, ptr);
|
2010-01-14 12:34:46 +01:00
|
|
|
currAssignment = 0;
|
|
|
|
|
} else {
|
2010-01-18 22:57:45 +01:00
|
|
|
updateItem(buf, ptr);
|
2010-01-14 12:34:46 +01:00
|
|
|
}
|
2009-08-07 19:17:44 +02:00
|
|
|
finalizeBlock();
|
2010-01-14 20:28:04 +01:00
|
|
|
if (c) {
|
|
|
|
|
++cur;
|
|
|
|
|
++m_lineNo;
|
|
|
|
|
goto freshLine;
|
|
|
|
|
}
|
2010-02-03 16:50:11 +01:00
|
|
|
m_block.reset();
|
|
|
|
|
m_blockstack.clear(); // FIXME: should actually check the state here
|
2010-01-14 20:28:04 +01:00
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-01-14 20:28:04 +01:00
|
|
|
if (c != ' ' && c != '\t' && c != '\r')
|
2009-08-07 19:17:44 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Then strip comments. Yep - no escaping is possible.
|
2010-01-14 20:28:04 +01:00
|
|
|
const ushort *end; // End of this line
|
|
|
|
|
const ushort *cptr; // Start of next line
|
|
|
|
|
for (cptr = cur;; ++cptr) {
|
|
|
|
|
c = *cptr;
|
|
|
|
|
if (c == '#') {
|
|
|
|
|
for (end = cptr; (c = *++cptr);) {
|
|
|
|
|
if (c == '\n') {
|
|
|
|
|
++cptr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (end == cur) { // Line with only a comment (sans whitespace)
|
2009-08-07 19:17:44 +02:00
|
|
|
// Qmake bizarreness: such lines do not affect line continuations
|
|
|
|
|
goto ignore;
|
2009-07-16 18:11:09 +02:00
|
|
|
}
|
2010-01-14 20:28:04 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!c) {
|
2009-08-07 19:17:44 +02:00
|
|
|
end = cptr;
|
|
|
|
|
break;
|
2009-07-16 18:11:09 +02:00
|
|
|
}
|
2010-01-14 20:28:04 +01:00
|
|
|
if (c == '\n') {
|
|
|
|
|
end = cptr++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-07 19:17:44 +02:00
|
|
|
|
2010-01-14 20:28:04 +01:00
|
|
|
// Then look for line continuations. Yep - no escaping here as well.
|
2009-08-07 19:17:44 +02:00
|
|
|
bool lineCont;
|
|
|
|
|
forever {
|
|
|
|
|
// We don't have to check for underrun here, as we already determined
|
|
|
|
|
// that the line is non-empty.
|
|
|
|
|
ushort ec = *(end - 1);
|
|
|
|
|
if (ec == '\\') {
|
|
|
|
|
--end;
|
|
|
|
|
lineCont = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-01-14 20:28:04 +01:00
|
|
|
if (ec != ' ' && ec != '\t' && ec != '\r') {
|
2009-08-07 19:17:44 +02:00
|
|
|
lineCont = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
--end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!inError) {
|
|
|
|
|
// Finally, do the tokenization
|
2010-01-14 12:34:46 +01:00
|
|
|
if (!currAssignment) {
|
2009-08-07 19:17:44 +02:00
|
|
|
newItem:
|
|
|
|
|
do {
|
|
|
|
|
if (cur == end)
|
|
|
|
|
goto lineEnd;
|
|
|
|
|
c = *cur++;
|
|
|
|
|
} while (c == ' ' || c == '\t');
|
|
|
|
|
forever {
|
|
|
|
|
if (c == '"') {
|
|
|
|
|
quote = '"' - quote;
|
|
|
|
|
} else if (!quote) {
|
|
|
|
|
if (c == '(') {
|
|
|
|
|
++parens;
|
|
|
|
|
} else if (c == ')') {
|
|
|
|
|
--parens;
|
|
|
|
|
} else if (!parens) {
|
|
|
|
|
if (c == ':') {
|
2010-01-18 22:57:45 +01:00
|
|
|
updateItem(buf, ptr);
|
2009-08-07 19:17:44 +02:00
|
|
|
enterScope(false);
|
|
|
|
|
nextItem:
|
2010-01-18 22:57:45 +01:00
|
|
|
ptr = buf;
|
2009-08-07 19:17:44 +02:00
|
|
|
putSpace = false;
|
|
|
|
|
goto newItem;
|
|
|
|
|
}
|
|
|
|
|
if (c == '{') {
|
2010-01-18 22:57:45 +01:00
|
|
|
updateItem(buf, ptr);
|
2009-08-07 19:17:44 +02:00
|
|
|
enterScope(true);
|
|
|
|
|
goto nextItem;
|
|
|
|
|
}
|
|
|
|
|
if (c == '}') {
|
2010-01-18 22:57:45 +01:00
|
|
|
updateItem(buf, ptr);
|
2009-08-07 19:17:44 +02:00
|
|
|
leaveScope();
|
|
|
|
|
goto nextItem;
|
|
|
|
|
}
|
|
|
|
|
if (c == '=') {
|
2010-01-18 22:57:45 +01:00
|
|
|
if ((currAssignment = startVariable(buf, ptr))) {
|
|
|
|
|
ptr = buf;
|
2009-08-07 19:17:44 +02:00
|
|
|
putSpace = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-01-18 22:57:45 +01:00
|
|
|
ptr = buf;
|
2009-08-07 19:17:44 +02:00
|
|
|
inError = true;
|
|
|
|
|
goto skip;
|
|
|
|
|
}
|
|
|
|
|
if (c == '|' || c == '!') {
|
2010-01-18 22:57:45 +01:00
|
|
|
updateItem(buf, ptr);
|
2009-08-07 19:17:44 +02:00
|
|
|
insertOperator(c);
|
|
|
|
|
goto nextItem;
|
|
|
|
|
}
|
2009-07-16 18:11:09 +02:00
|
|
|
}
|
2009-08-07 19:17:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (putSpace) {
|
|
|
|
|
putSpace = false;
|
|
|
|
|
*ptr++ = ' ';
|
|
|
|
|
}
|
|
|
|
|
*ptr++ = c;
|
|
|
|
|
|
|
|
|
|
forever {
|
|
|
|
|
if (cur == end)
|
|
|
|
|
goto lineEnd;
|
|
|
|
|
c = *cur++;
|
|
|
|
|
if (c != ' ' && c != '\t')
|
|
|
|
|
break;
|
|
|
|
|
putSpace = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-01-14 12:34:46 +01:00
|
|
|
} // !currAssignment
|
2009-08-07 19:17:44 +02:00
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
if (cur == end)
|
|
|
|
|
goto lineEnd;
|
|
|
|
|
c = *cur++;
|
|
|
|
|
} while (c == ' ' || c == '\t');
|
2010-01-14 12:34:46 +01:00
|
|
|
forever {
|
|
|
|
|
if (putSpace) {
|
|
|
|
|
putSpace = false;
|
|
|
|
|
*ptr++ = ' ';
|
2009-07-21 15:51:51 +02:00
|
|
|
}
|
2010-01-14 12:34:46 +01:00
|
|
|
*ptr++ = c;
|
2009-08-07 19:17:44 +02:00
|
|
|
|
2010-01-14 12:34:46 +01:00
|
|
|
forever {
|
|
|
|
|
if (cur == end)
|
|
|
|
|
goto lineEnd;
|
|
|
|
|
c = *cur++;
|
|
|
|
|
if (c != ' ' && c != '\t')
|
|
|
|
|
break;
|
|
|
|
|
putSpace = true;
|
2009-08-07 19:17:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lineEnd:
|
|
|
|
|
if (lineCont) {
|
2010-01-18 22:57:45 +01:00
|
|
|
putSpace = (ptr != buf);
|
2009-07-16 18:11:09 +02:00
|
|
|
} else {
|
2010-01-14 12:34:46 +01:00
|
|
|
if (currAssignment) {
|
2010-01-18 22:57:45 +01:00
|
|
|
finalizeVariable(currAssignment, buf, ptr);
|
2010-01-14 12:34:46 +01:00
|
|
|
currAssignment = 0;
|
|
|
|
|
} else {
|
2010-01-18 22:57:45 +01:00
|
|
|
updateItem(buf, ptr);
|
2010-01-14 12:34:46 +01:00
|
|
|
}
|
2010-01-18 22:57:45 +01:00
|
|
|
ptr = buf;
|
2009-08-07 19:17:44 +02:00
|
|
|
putSpace = false;
|
2009-07-16 18:11:09 +02:00
|
|
|
}
|
2009-08-07 19:17:44 +02:00
|
|
|
} // !inError
|
|
|
|
|
skip:
|
|
|
|
|
if (!lineCont) {
|
2009-07-16 18:11:09 +02:00
|
|
|
finalizeBlock();
|
2010-01-14 20:28:04 +01:00
|
|
|
cur = cptr;
|
2009-08-07 19:17:44 +02:00
|
|
|
++m_lineNo;
|
|
|
|
|
goto freshLine;
|
|
|
|
|
}
|
|
|
|
|
ignore:
|
2010-01-14 20:28:04 +01:00
|
|
|
cur = cptr;
|
2009-07-16 18:11:09 +02:00
|
|
|
++m_lineNo;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::finalizeBlock()
|
|
|
|
|
{
|
2010-02-03 16:50:11 +01:00
|
|
|
if (m_blockstack.top().block->blockKind() & ProBlock::SingleLine)
|
2009-07-16 17:22:03 +02:00
|
|
|
leaveScope();
|
2010-02-03 16:50:11 +01:00
|
|
|
m_block.reset();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-01-18 22:57:45 +01:00
|
|
|
ProVariable *ProFileEvaluator::Private::startVariable(ushort *uc, ushort *ptr)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
ProVariable::VariableOperator opkind;
|
|
|
|
|
|
2009-07-15 09:58:56 +02:00
|
|
|
if (ptr == uc) // Line starting with '=', like a conflict marker
|
2010-01-14 12:34:46 +01:00
|
|
|
return 0;
|
2009-04-14 14:35:32 +02:00
|
|
|
|
2009-07-15 09:58:56 +02:00
|
|
|
switch (*(ptr - 1)) {
|
2008-12-02 12:01:29 +01:00
|
|
|
case '+':
|
2009-07-15 09:58:56 +02:00
|
|
|
--ptr;
|
2008-12-02 12:01:29 +01:00
|
|
|
opkind = ProVariable::AddOperator;
|
|
|
|
|
break;
|
|
|
|
|
case '-':
|
2009-07-15 09:58:56 +02:00
|
|
|
--ptr;
|
2008-12-02 12:01:29 +01:00
|
|
|
opkind = ProVariable::RemoveOperator;
|
|
|
|
|
break;
|
|
|
|
|
case '*':
|
2009-07-15 09:58:56 +02:00
|
|
|
--ptr;
|
2008-12-02 12:01:29 +01:00
|
|
|
opkind = ProVariable::UniqueAddOperator;
|
|
|
|
|
break;
|
|
|
|
|
case '~':
|
2009-07-15 09:58:56 +02:00
|
|
|
--ptr;
|
2008-12-02 12:01:29 +01:00
|
|
|
opkind = ProVariable::ReplaceOperator;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
opkind = ProVariable::SetOperator;
|
2009-08-07 19:17:44 +02:00
|
|
|
goto skipTrunc;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-08-07 19:17:44 +02:00
|
|
|
if (ptr == uc) // Line starting with manipulation operator
|
2010-01-14 12:34:46 +01:00
|
|
|
return 0;
|
2009-08-07 19:17:44 +02:00
|
|
|
if (*(ptr - 1) == ' ')
|
2009-07-15 09:58:56 +02:00
|
|
|
--ptr;
|
2009-08-07 19:17:44 +02:00
|
|
|
|
|
|
|
|
skipTrunc:
|
2010-02-11 16:33:16 +01:00
|
|
|
ProVariable *variable = new ProVariable(map(QString((QChar*)uc, ptr - uc)));
|
2008-12-02 12:01:29 +01:00
|
|
|
variable->setLineNumber(m_lineNo);
|
|
|
|
|
variable->setVariableOperator(opkind);
|
2010-01-14 12:34:46 +01:00
|
|
|
return variable;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-18 22:57:45 +01:00
|
|
|
void ProFileEvaluator::Private::finalizeVariable(ProVariable *variable, ushort *uc, ushort *ptr)
|
2010-01-14 12:34:46 +01:00
|
|
|
{
|
2010-01-18 22:57:45 +01:00
|
|
|
variable->setValue(QString((QChar*)uc, ptr - uc));
|
2009-07-15 09:58:56 +02:00
|
|
|
|
2010-02-03 16:50:11 +01:00
|
|
|
m_blockstack.top().append(variable);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::insertOperator(const char op)
|
|
|
|
|
{
|
|
|
|
|
ProOperator::OperatorKind opkind;
|
2008-12-09 11:07:24 +01:00
|
|
|
switch (op) {
|
2008-12-02 12:01:29 +01:00
|
|
|
case '!':
|
|
|
|
|
opkind = ProOperator::NotOperator;
|
|
|
|
|
break;
|
|
|
|
|
case '|':
|
|
|
|
|
opkind = ProOperator::OrOperator;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
opkind = ProOperator::OrOperator;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProOperator * const proOp = new ProOperator(opkind);
|
|
|
|
|
proOp->setLineNumber(m_lineNo);
|
2010-02-03 16:50:11 +01:00
|
|
|
currentBlock().append(proOp);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::enterScope(bool multiLine)
|
|
|
|
|
{
|
2010-02-03 16:50:11 +01:00
|
|
|
BlockCursor &parent = currentBlock();
|
|
|
|
|
|
2010-02-03 10:08:45 +01:00
|
|
|
ProBlock *block = new ProBlock();
|
2008-12-02 12:01:29 +01:00
|
|
|
block->setLineNumber(m_lineNo);
|
|
|
|
|
if (multiLine)
|
|
|
|
|
block->setBlockKind(ProBlock::ScopeContentsKind);
|
|
|
|
|
else
|
|
|
|
|
block->setBlockKind(ProBlock::ScopeContentsKind|ProBlock::SingleLine);
|
2010-02-03 16:50:11 +01:00
|
|
|
m_blockstack.push(BlockCursor(block));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-03 16:50:11 +01:00
|
|
|
parent.block->setBlockKind(ProBlock::ScopeKind);
|
|
|
|
|
parent.append(block);
|
|
|
|
|
|
|
|
|
|
m_block.reset();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::leaveScope()
|
|
|
|
|
{
|
2009-07-16 17:22:03 +02:00
|
|
|
if (m_blockstack.count() == 1)
|
2009-08-12 13:00:21 +02:00
|
|
|
errorMessage(format("Excess closing brace."));
|
2009-07-16 17:22:03 +02:00
|
|
|
else
|
|
|
|
|
m_blockstack.pop();
|
2008-12-02 12:01:29 +01:00
|
|
|
finalizeBlock();
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 16:50:11 +01:00
|
|
|
ProFileEvaluator::Private::BlockCursor &ProFileEvaluator::Private::currentBlock()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-02-03 16:50:11 +01:00
|
|
|
if (!m_block.isValid()) {
|
|
|
|
|
ProBlock *blk = new ProBlock();
|
|
|
|
|
blk->setLineNumber(m_lineNo);
|
|
|
|
|
m_blockstack.top().append(blk);
|
|
|
|
|
m_block.set(blk);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
return m_block;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-18 22:57:45 +01:00
|
|
|
void ProFileEvaluator::Private::updateItem(ushort *uc, ushort *ptr)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-01-18 22:57:45 +01:00
|
|
|
if (ptr == uc)
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
|
2010-01-18 22:57:45 +01:00
|
|
|
QString proItem = QString((QChar*)uc, ptr - uc);
|
2009-07-15 09:58:56 +02:00
|
|
|
|
2010-01-18 18:23:12 +01:00
|
|
|
ProItem *item;
|
2010-01-14 12:34:46 +01:00
|
|
|
if (proItem.endsWith(QLatin1Char(')'))) {
|
2010-01-18 18:23:12 +01:00
|
|
|
item = new ProFunction(proItem);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-01-18 18:23:12 +01:00
|
|
|
item = new ProCondition(proItem);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-01-18 18:23:12 +01:00
|
|
|
item->setLineNumber(m_lineNo);
|
2010-02-03 16:50:11 +01:00
|
|
|
currentBlock().append(item);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
//////// Evaluator tools /////////
|
|
|
|
|
|
2010-01-14 17:43:02 +01:00
|
|
|
QStringList ProFileEvaluator::Private::split_value_list(const QString &vals)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
QString build;
|
|
|
|
|
QStringList ret;
|
|
|
|
|
QStack<char> quote;
|
|
|
|
|
|
2009-07-23 18:36:59 +02:00
|
|
|
const ushort SPACE = ' ';
|
2009-07-23 16:34:30 +02:00
|
|
|
const ushort LPAREN = '(';
|
|
|
|
|
const ushort RPAREN = ')';
|
|
|
|
|
const ushort SINGLEQUOTE = '\'';
|
|
|
|
|
const ushort DOUBLEQUOTE = '"';
|
|
|
|
|
const ushort BACKSLASH = '\\';
|
|
|
|
|
|
|
|
|
|
ushort unicode;
|
|
|
|
|
const QChar *vals_data = vals.data();
|
|
|
|
|
const int vals_len = vals.length();
|
|
|
|
|
for (int x = 0, parens = 0; x < vals_len; x++) {
|
|
|
|
|
unicode = vals_data[x].unicode();
|
|
|
|
|
if (x != (int)vals_len-1 && unicode == BACKSLASH &&
|
|
|
|
|
(vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) {
|
|
|
|
|
build += vals_data[x++]; //get that 'escape'
|
|
|
|
|
} 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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-14 17:43:02 +01:00
|
|
|
if (!parens && quote.isEmpty() && vals_data[x] == SPACE) {
|
2009-07-23 16:34:30 +02:00
|
|
|
ret << build;
|
|
|
|
|
build.clear();
|
|
|
|
|
} else {
|
|
|
|
|
build += vals_data[x];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!build.isEmpty())
|
|
|
|
|
ret << build;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-09 15:44:17 +01:00
|
|
|
static void insertUnique(QStringList *varlist, const QStringList &value)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
foreach (const QString &str, value)
|
2010-02-09 15:44:17 +01:00
|
|
|
if (!varlist->contains(str))
|
|
|
|
|
varlist->append(str);
|
2009-07-23 16:34:30 +02:00
|
|
|
}
|
|
|
|
|
|
2010-02-09 15:44:17 +01:00
|
|
|
static void removeEach(QStringList *varlist, const QStringList &value)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
foreach (const QString &str, value)
|
2010-02-09 15:44:17 +01:00
|
|
|
varlist->removeAll(str);
|
2009-07-23 16:34:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void replaceInList(QStringList *varlist,
|
|
|
|
|
const QRegExp ®exp, const QString &replace, bool global)
|
|
|
|
|
{
|
|
|
|
|
for (QStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
|
|
|
|
|
if ((*varit).contains(regexp)) {
|
|
|
|
|
(*varit).replace(regexp, replace);
|
|
|
|
|
if ((*varit).isEmpty())
|
|
|
|
|
varit = varlist->erase(varit);
|
|
|
|
|
else
|
|
|
|
|
++varit;
|
|
|
|
|
if (!global)
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
++varit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 17:04:50 +02:00
|
|
|
static QString expandEnvVars(const QString &str)
|
|
|
|
|
{
|
|
|
|
|
QString string = str;
|
|
|
|
|
int rep;
|
2010-02-08 17:15:44 +01:00
|
|
|
QRegExp reg_variableName = statics.reg_variableName; // Copy for thread safety
|
2009-07-23 17:04:50 +02:00
|
|
|
while ((rep = reg_variableName.indexIn(string)) != -1)
|
|
|
|
|
string.replace(rep, reg_variableName.matchedLength(),
|
|
|
|
|
QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_variableName.matchedLength() - 3).toLatin1().constData()).constData()));
|
|
|
|
|
return string;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-30 17:03:12 +02:00
|
|
|
static QStringList expandEnvVars(const QStringList &x)
|
|
|
|
|
{
|
|
|
|
|
QStringList ret;
|
|
|
|
|
foreach (const QString &str, x)
|
|
|
|
|
ret << expandEnvVars(str);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 17:04:50 +02:00
|
|
|
// This is braindead, but we want qmake compat
|
|
|
|
|
static QString fixPathToLocalOS(const QString &str)
|
|
|
|
|
{
|
2010-02-11 12:42:40 +01:00
|
|
|
QString string = expandEnvVars(str);
|
2009-07-23 17:04:50 +02:00
|
|
|
|
2009-08-04 20:51:49 +02:00
|
|
|
if (string.length() > 2 && string.at(0).isLetter() && string.at(1) == QLatin1Char(':'))
|
2009-07-23 17:04:50 +02:00
|
|
|
string[0] = string[0].toLower();
|
|
|
|
|
|
|
|
|
|
#if defined(Q_OS_WIN32)
|
|
|
|
|
string.replace(QLatin1Char('/'), QLatin1Char('\\'));
|
|
|
|
|
#else
|
|
|
|
|
string.replace(QLatin1Char('\\'), QLatin1Char('/'));
|
|
|
|
|
#endif
|
|
|
|
|
return string;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
//////// Evaluator /////////
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-02 21:00:09 +01:00
|
|
|
ProItem::ProItemReturn ProFileEvaluator::Private::visitProItem(ProItem *item)
|
|
|
|
|
{
|
|
|
|
|
switch (item->kind()) {
|
|
|
|
|
case ProItem::BlockKind: // This is never a ProFile
|
|
|
|
|
return visitProBlock(static_cast<ProBlock*>(item));
|
|
|
|
|
case ProItem::VariableKind:
|
|
|
|
|
visitProVariable(static_cast<ProVariable*>(item));
|
|
|
|
|
break;
|
|
|
|
|
case ProItem::ConditionKind:
|
|
|
|
|
visitProCondition(static_cast<ProCondition*>(item));
|
|
|
|
|
break;
|
|
|
|
|
case ProItem::FunctionKind:
|
|
|
|
|
return visitProFunction(static_cast<ProFunction*>(item));
|
|
|
|
|
case ProItem::OperatorKind:
|
|
|
|
|
visitProOperator(static_cast<ProOperator*>(item));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProItem::ProItemReturn ProFileEvaluator::Private::visitProBlock(ProBlock *block)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-05-14 14:35:37 +02:00
|
|
|
if (block->blockKind() & ProBlock::ScopeContentsKind) {
|
2009-05-18 17:46:30 +02:00
|
|
|
if (!m_definingFunc.isEmpty()) {
|
|
|
|
|
if (!m_skipLevel || m_cumulative) {
|
|
|
|
|
QHash<QString, ProBlock *> *hash =
|
2009-08-10 17:27:07 +02:00
|
|
|
(m_definingTest ? &m_functionDefs.testFunctions
|
|
|
|
|
: &m_functionDefs.replaceFunctions);
|
2009-05-18 17:46:30 +02:00
|
|
|
if (ProBlock *def = hash->value(m_definingFunc))
|
|
|
|
|
def->deref();
|
|
|
|
|
hash->insert(m_definingFunc, block);
|
|
|
|
|
block->ref();
|
|
|
|
|
block->setBlockKind(block->blockKind() | ProBlock::FunctionBodyKind);
|
|
|
|
|
}
|
|
|
|
|
m_definingFunc.clear();
|
2010-02-02 21:00:09 +01:00
|
|
|
return ProItem::ReturnTrue;
|
2009-05-18 17:46:30 +02:00
|
|
|
} else if (!(block->blockKind() & ProBlock::FunctionBodyKind)) {
|
2009-08-14 14:36:34 +02:00
|
|
|
if (!m_sts.condition) {
|
|
|
|
|
if (m_skipLevel || m_hadCondition)
|
|
|
|
|
++m_skipLevel;
|
|
|
|
|
} else {
|
2009-05-18 17:46:30 +02:00
|
|
|
Q_ASSERT(!m_skipLevel);
|
2009-08-14 14:36:34 +02:00
|
|
|
}
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
2009-05-14 14:35:37 +02:00
|
|
|
} else {
|
2009-08-14 14:36:34 +02:00
|
|
|
m_hadCondition = false;
|
2009-05-14 14:35:37 +02:00
|
|
|
if (!m_skipLevel) {
|
|
|
|
|
if (m_sts.condition) {
|
|
|
|
|
m_sts.prevCondition = true;
|
|
|
|
|
m_sts.condition = false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Q_ASSERT(!m_sts.condition);
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-02 21:00:09 +01:00
|
|
|
ProItem::ProItemReturn rt = ProItem::ReturnTrue;
|
2010-02-03 16:50:11 +01:00
|
|
|
for (ProItem *item = block->items(); item; item = item->next()) {
|
|
|
|
|
rt = visitProItem(item);
|
2010-02-02 21:00:09 +01:00
|
|
|
if (rt != ProItem::ReturnTrue && rt != ProItem::ReturnFalse) {
|
|
|
|
|
if (rt == ProItem::ReturnLoop) {
|
|
|
|
|
rt = ProItem::ReturnTrue;
|
|
|
|
|
while (visitProLoopIteration())
|
2010-02-03 16:50:11 +01:00
|
|
|
for (ProItem *lItem = item; (lItem = lItem->next()); ) {
|
|
|
|
|
rt = visitProItem(lItem);
|
2010-02-02 21:00:09 +01:00
|
|
|
if (rt != ProItem::ReturnTrue && rt != ProItem::ReturnFalse) {
|
|
|
|
|
if (rt == ProItem::ReturnNext) {
|
|
|
|
|
rt = ProItem::ReturnTrue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (rt == ProItem::ReturnBreak)
|
|
|
|
|
rt = ProItem::ReturnTrue;
|
|
|
|
|
goto do_break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
do_break:
|
|
|
|
|
visitProLoopCleanup();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-05-18 17:46:30 +02:00
|
|
|
if ((block->blockKind() & ProBlock::ScopeContentsKind)
|
|
|
|
|
&& !(block->blockKind() & ProBlock::FunctionBodyKind)) {
|
2008-12-16 10:48:49 +01:00
|
|
|
if (m_skipLevel) {
|
2009-05-14 14:35:37 +02:00
|
|
|
Q_ASSERT(!m_sts.condition);
|
2008-12-12 18:10:42 +01:00
|
|
|
--m_skipLevel;
|
2009-05-14 14:35:37 +02:00
|
|
|
} else if (!(block->blockKind() & ProBlock::SingleLine)) {
|
2008-12-16 10:48:49 +01:00
|
|
|
// Conditionals contained inside this block may have changed the state.
|
|
|
|
|
// So we reset it here to make an else following us do the right thing.
|
2009-05-14 14:35:37 +02:00
|
|
|
m_sts.condition = true;
|
2008-12-16 10:48:49 +01:00
|
|
|
}
|
2008-12-12 18:10:42 +01:00
|
|
|
}
|
2010-02-02 21:00:09 +01:00
|
|
|
return rt;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-05-19 19:00:06 +02:00
|
|
|
ProItem::ProItemReturn ProFileEvaluator::Private::visitProLoopIteration()
|
|
|
|
|
{
|
|
|
|
|
ProLoop &loop = m_loopStack.top();
|
|
|
|
|
|
|
|
|
|
if (loop.infinite) {
|
|
|
|
|
if (!loop.variable.isEmpty())
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top()[loop.variable] = QStringList(QString::number(loop.index++));
|
2009-05-19 19:00:06 +02:00
|
|
|
if (loop.index > 1000) {
|
2009-08-12 13:00:21 +02:00
|
|
|
errorMessage(format("ran into infinite loop (> 1000 iterations)."));
|
2009-05-19 19:00:06 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
QString val;
|
|
|
|
|
do {
|
|
|
|
|
if (loop.index >= loop.list.count())
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
val = loop.list.at(loop.index++);
|
|
|
|
|
} while (val.isEmpty()); // stupid, but qmake is like that
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top()[loop.variable] = QStringList(val);
|
2009-05-19 19:00:06 +02:00
|
|
|
}
|
|
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::visitProLoopCleanup()
|
|
|
|
|
{
|
|
|
|
|
ProLoop &loop = m_loopStack.top();
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top()[loop.variable] = loop.oldVarVal;
|
2009-05-19 19:00:06 +02:00
|
|
|
m_loopStack.pop_back();
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-14 12:34:46 +01:00
|
|
|
void ProFileEvaluator::Private::visitProVariable(ProVariable *var)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-01-14 12:34:46 +01:00
|
|
|
m_lineNo = var->lineNumber();
|
|
|
|
|
const QString &varName = var->variable();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-14 12:34:46 +01:00
|
|
|
if (var->variableOperator() == ProVariable::ReplaceOperator) { // ~=
|
|
|
|
|
// DEFINES ~= s/a/b/?[gqi]
|
2009-07-14 20:42:45 +02:00
|
|
|
|
2010-01-14 12:34:46 +01:00
|
|
|
QString val = var->value();
|
|
|
|
|
doVariableReplace(&val);
|
|
|
|
|
if (val.length() < 4 || val.at(0) != QLatin1Char('s')) {
|
|
|
|
|
logMessage(format("the ~= operator can handle only the s/// function."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
QChar sep = val.at(1);
|
|
|
|
|
QStringList func = val.split(sep);
|
|
|
|
|
if (func.count() < 3 || func.count() > 4) {
|
|
|
|
|
logMessage(format("the s/// function expects 3 or 4 arguments."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool global = false, quote = false, case_sense = false;
|
|
|
|
|
if (func.count() == 4) {
|
|
|
|
|
global = func[3].indexOf(QLatin1Char('g')) != -1;
|
|
|
|
|
case_sense = func[3].indexOf(QLatin1Char('i')) == -1;
|
|
|
|
|
quote = func[3].indexOf(QLatin1Char('q')) != -1;
|
|
|
|
|
}
|
|
|
|
|
QString pattern = func[1];
|
|
|
|
|
QString replace = func[2];
|
|
|
|
|
if (quote)
|
|
|
|
|
pattern = QRegExp::escape(pattern);
|
|
|
|
|
|
|
|
|
|
QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
|
|
|
|
|
|
|
|
|
if (!m_skipLevel || m_cumulative) {
|
|
|
|
|
// We could make a union of modified and unmodified values,
|
|
|
|
|
// but this will break just as much as it fixes, so leave it as is.
|
2010-02-09 20:38:21 +01:00
|
|
|
replaceInList(&valuesRef(varName), regexp, replace, global);
|
2010-01-14 12:34:46 +01:00
|
|
|
replaceInList(&m_filevaluemap[currentProFile()][varName], regexp, replace, global);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2010-02-08 16:47:25 +01:00
|
|
|
bool doSemicolon = (varName == statics.deppath || varName == statics.incpath);
|
2010-01-14 17:43:02 +01:00
|
|
|
QStringList varVal = expandVariableReferences(var->value(), doSemicolon);
|
2010-01-14 12:34:46 +01:00
|
|
|
|
|
|
|
|
switch (var->variableOperator()) {
|
|
|
|
|
default: // ReplaceOperator - cannot happen
|
2009-07-14 20:42:45 +02:00
|
|
|
case ProVariable::SetOperator: // =
|
|
|
|
|
if (!m_cumulative) {
|
|
|
|
|
if (!m_skipLevel) {
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top()[varName] = varVal;
|
2010-01-14 12:34:46 +01:00
|
|
|
m_filevaluemap[currentProFile()][varName] = varVal;
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// We are greedy for values.
|
2010-02-09 20:38:21 +01:00
|
|
|
valuesRef(varName) += varVal;
|
2010-01-14 12:34:46 +01:00
|
|
|
m_filevaluemap[currentProFile()][varName] += varVal;
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ProVariable::UniqueAddOperator: // *=
|
|
|
|
|
if (!m_skipLevel || m_cumulative) {
|
2010-02-09 20:38:21 +01:00
|
|
|
insertUnique(&valuesRef(varName), varVal);
|
2010-02-09 15:44:17 +01:00
|
|
|
insertUnique(&m_filevaluemap[currentProFile()][varName], varVal);
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ProVariable::AddOperator: // +=
|
|
|
|
|
if (!m_skipLevel || m_cumulative) {
|
2010-02-09 20:38:21 +01:00
|
|
|
valuesRef(varName) += varVal;
|
2010-01-14 12:34:46 +01:00
|
|
|
m_filevaluemap[currentProFile()][varName] += varVal;
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ProVariable::RemoveOperator: // -=
|
|
|
|
|
if (!m_cumulative) {
|
|
|
|
|
if (!m_skipLevel) {
|
2010-02-09 20:38:21 +01:00
|
|
|
removeEach(&valuesRef(varName), varVal);
|
2010-02-09 15:44:17 +01:00
|
|
|
removeEach(&m_filevaluemap[currentProFile()][varName], varVal);
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// We are stingy with our values, too.
|
|
|
|
|
}
|
|
|
|
|
break;
|
2010-01-14 12:34:46 +01:00
|
|
|
}
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-05-18 17:25:41 +02:00
|
|
|
void ProFileEvaluator::Private::visitProOperator(ProOperator *oper)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
m_invertNext = (oper->operatorKind() == ProOperator::NotOperator);
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-18 17:25:41 +02:00
|
|
|
void ProFileEvaluator::Private::visitProCondition(ProCondition *cond)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2008-12-12 18:10:42 +01:00
|
|
|
if (!m_skipLevel) {
|
2009-08-14 14:36:34 +02:00
|
|
|
m_hadCondition = true;
|
2010-02-08 17:15:44 +01:00
|
|
|
if (!cond->text().compare(statics.strelse, Qt::CaseInsensitive)) {
|
2009-05-14 14:35:37 +02:00
|
|
|
m_sts.condition = !m_sts.prevCondition;
|
|
|
|
|
} else {
|
|
|
|
|
m_sts.prevCondition = false;
|
|
|
|
|
if (!m_sts.condition && isActiveConfig(cond->text(), true) ^ m_invertNext)
|
|
|
|
|
m_sts.condition = true;
|
2008-12-12 18:10:42 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-12 18:10:42 +01:00
|
|
|
m_invertNext = false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-02-02 21:00:09 +01:00
|
|
|
ProItem::ProItemReturn ProFileEvaluator::Private::visitProFile(ProFile *pro)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
m_lineNo = pro->lineNumber();
|
2009-07-28 18:54:03 +02:00
|
|
|
|
2009-07-22 17:46:25 +02:00
|
|
|
m_profileStack.push(pro);
|
|
|
|
|
if (m_profileStack.count() == 1) {
|
2009-07-28 18:54:03 +02:00
|
|
|
// Do this only for the initial profile we visit, since
|
2008-12-02 12:01:29 +01:00
|
|
|
// that is *the* profile. All the other times we reach this function will be due to
|
|
|
|
|
// include(file) or load(file)
|
|
|
|
|
|
2009-07-22 11:03:01 +02:00
|
|
|
if (m_parsePreAndPostFiles) {
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2010-06-04 17:08:27 +02:00
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
|
|
|
|
{
|
|
|
|
|
QMutexLocker locker(&m_option->mutex);
|
|
|
|
|
if (m_option->base_inProgress) {
|
|
|
|
|
QThreadPool::globalInstance()->releaseThread();
|
|
|
|
|
m_option->cond.wait(&m_option->mutex);
|
|
|
|
|
QThreadPool::globalInstance()->reserveThread();
|
|
|
|
|
} else
|
|
|
|
|
#endif
|
2009-08-04 16:16:27 +02:00
|
|
|
if (m_option->base_valuemap.isEmpty()) {
|
2010-06-04 17:08:27 +02:00
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
|
|
|
|
m_option->base_inProgress = true;
|
|
|
|
|
locker.unlock();
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-08-04 16:16:27 +02:00
|
|
|
// ### init QMAKE_QMAKE, QMAKE_SH
|
|
|
|
|
// ### init QMAKE_EXT_{C,H,CPP,OBJ}
|
|
|
|
|
// ### init TEMPLATE_PREFIX
|
|
|
|
|
|
|
|
|
|
QString qmake_cache = m_option->cachefile;
|
|
|
|
|
if (qmake_cache.isEmpty() && !m_outputDir.isEmpty()) { //find it as it has not been specified
|
|
|
|
|
QDir dir(m_outputDir);
|
|
|
|
|
forever {
|
2010-01-22 12:26:14 +01:00
|
|
|
qmake_cache = dir.path() + QLatin1String("/.qmake.cache");
|
|
|
|
|
if (IoUtils::exists(qmake_cache))
|
2009-08-04 16:16:27 +02:00
|
|
|
break;
|
2009-08-05 12:18:36 +02:00
|
|
|
if (!dir.cdUp() || dir.isRoot()) {
|
2009-08-04 16:16:27 +02:00
|
|
|
qmake_cache.clear();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!qmake_cache.isEmpty()) {
|
2010-02-05 19:24:33 +01:00
|
|
|
qmake_cache = resolvePath(qmake_cache);
|
2009-09-08 14:13:50 +02:00
|
|
|
QHash<QString, QStringList> cache_valuemap;
|
|
|
|
|
if (evaluateFileInto(qmake_cache, &cache_valuemap, 0)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
if (m_option->qmakespec.isEmpty()) {
|
2009-09-08 14:13:50 +02:00
|
|
|
const QStringList &vals = cache_valuemap.value(QLatin1String("QMAKESPEC"));
|
2009-08-04 16:16:27 +02:00
|
|
|
if (!vals.isEmpty())
|
|
|
|
|
m_option->qmakespec = vals.first();
|
|
|
|
|
}
|
2010-02-05 19:24:33 +01:00
|
|
|
} else {
|
|
|
|
|
qmake_cache.clear();
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-02-05 19:24:33 +01:00
|
|
|
m_option->cachefile = qmake_cache;
|
2009-08-04 16:16:27 +02:00
|
|
|
|
|
|
|
|
QStringList mkspec_roots = qmakeMkspecPaths();
|
|
|
|
|
|
|
|
|
|
QString qmakespec = expandEnvVars(m_option->qmakespec);
|
|
|
|
|
if (qmakespec.isEmpty()) {
|
|
|
|
|
foreach (const QString &root, mkspec_roots) {
|
|
|
|
|
QString mkspec = root + QLatin1String("/default");
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::fileType(mkspec) == IoUtils::FileIsDir) {
|
2009-08-04 16:16:27 +02:00
|
|
|
qmakespec = mkspec;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (qmakespec.isEmpty()) {
|
2009-08-12 13:00:21 +02:00
|
|
|
errorMessage(format("Could not find qmake configuration directory"));
|
2009-08-04 16:16:27 +02:00
|
|
|
// Unlike in qmake, not finding the spec is not critical ...
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::isRelativePath(qmakespec)) {
|
2010-02-03 18:16:46 +01:00
|
|
|
if (IoUtils::exists(currentDirectory() + QLatin1Char('/') + qmakespec
|
|
|
|
|
+ QLatin1String("/qmake.conf"))) {
|
2010-01-22 12:26:14 +01:00
|
|
|
qmakespec = currentDirectory() + QLatin1Char('/') + qmakespec;
|
2009-08-04 16:16:27 +02:00
|
|
|
} else if (!m_outputDir.isEmpty()
|
2010-01-22 12:26:14 +01:00
|
|
|
&& IoUtils::exists(m_outputDir + QLatin1Char('/') + qmakespec
|
|
|
|
|
+ QLatin1String("/qmake.conf"))) {
|
2009-08-04 16:16:27 +02:00
|
|
|
qmakespec = m_outputDir + QLatin1Char('/') + qmakespec;
|
|
|
|
|
} else {
|
|
|
|
|
foreach (const QString &root, mkspec_roots) {
|
|
|
|
|
QString mkspec = root + QLatin1Char('/') + qmakespec;
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(mkspec)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
qmakespec = mkspec;
|
|
|
|
|
goto cool;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-12 13:00:21 +02:00
|
|
|
errorMessage(format("Could not find qmake configuration file"));
|
2009-08-04 16:16:27 +02:00
|
|
|
// Unlike in qmake, a missing config is not critical ...
|
|
|
|
|
qmakespec.clear();
|
|
|
|
|
cool: ;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!qmakespec.isEmpty()) {
|
|
|
|
|
m_option->qmakespec = QDir::cleanPath(qmakespec);
|
|
|
|
|
|
|
|
|
|
QString spec = m_option->qmakespec + QLatin1String("/qmake.conf");
|
2009-08-10 17:27:07 +02:00
|
|
|
if (!evaluateFileInto(spec,
|
|
|
|
|
&m_option->base_valuemap, &m_option->base_functions)) {
|
2009-08-12 13:00:21 +02:00
|
|
|
errorMessage(format("Could not read qmake configuration file %1").arg(spec));
|
2009-09-08 14:19:34 +02:00
|
|
|
} else if (!m_option->cachefile.isEmpty()) {
|
|
|
|
|
evaluateFileInto(m_option->cachefile,
|
2009-09-08 14:18:06 +02:00
|
|
|
&m_option->base_valuemap, &m_option->base_functions);
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
2010-02-10 15:35:57 +01:00
|
|
|
m_option->qmakespec_name = IoUtils::fileName(m_option->qmakespec).toString();
|
|
|
|
|
if (m_option->qmakespec_name == QLatin1String("default")) {
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
char buffer[1024];
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
int l = ::readlink(m_option->qmakespec.toLocal8Bit().constData(), buffer, 1024);
|
2010-02-10 15:35:57 +01:00
|
|
|
if (l != -1)
|
|
|
|
|
m_option->qmakespec_name =
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
IoUtils::fileName(QString::fromLocal8Bit(buffer, l)).toString();
|
2010-02-10 15:35:57 +01:00
|
|
|
#else
|
|
|
|
|
// We can't resolve symlinks as they do on Unix, so configure.exe puts
|
|
|
|
|
// the source of the qmake.conf at the end of the default/qmake.conf in
|
|
|
|
|
// the QMAKESPEC_ORG variable.
|
|
|
|
|
const QStringList &spec_org =
|
|
|
|
|
m_option->base_valuemap.value(QLatin1String("QMAKESPEC_ORIGINAL"));
|
|
|
|
|
if (!spec_org.isEmpty())
|
|
|
|
|
m_option->qmakespec_name =
|
|
|
|
|
IoUtils::fileName(spec_org.first()).toString();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
|
2009-08-10 17:27:07 +02:00
|
|
|
evaluateFeatureFile(QLatin1String("default_pre.prf"),
|
|
|
|
|
&m_option->base_valuemap, &m_option->base_functions);
|
2010-06-04 17:08:27 +02:00
|
|
|
|
|
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
|
|
|
|
locker.relock();
|
|
|
|
|
m_option->base_inProgress = false;
|
|
|
|
|
m_option->cond.wakeAll();
|
|
|
|
|
#endif
|
2009-07-22 11:03:01 +02:00
|
|
|
}
|
2010-06-04 17:08:27 +02:00
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top() = m_option->base_valuemap;
|
2009-03-19 15:04:43 +01:00
|
|
|
|
2009-08-10 17:27:07 +02:00
|
|
|
clearFunctions(&m_functionDefs);
|
|
|
|
|
m_functionDefs = m_option->base_functions;
|
|
|
|
|
refFunctions(&m_functionDefs.testFunctions);
|
|
|
|
|
refFunctions(&m_functionDefs.replaceFunctions);
|
|
|
|
|
|
2010-02-09 20:38:21 +01:00
|
|
|
QStringList &tgt = m_valuemapStack.top()[QLatin1String("TARGET")];
|
2009-07-29 11:30:33 +02:00
|
|
|
if (tgt.isEmpty())
|
|
|
|
|
tgt.append(QFileInfo(pro->fileName()).baseName());
|
|
|
|
|
|
2010-02-09 20:38:21 +01:00
|
|
|
QStringList &tmp = m_valuemapStack.top()[QLatin1String("CONFIG")];
|
2009-03-19 15:04:43 +01:00
|
|
|
tmp.append(m_addUserConfigCmdArgs);
|
2009-07-22 11:03:01 +02:00
|
|
|
foreach (const QString &remove, m_removeUserConfigCmdArgs)
|
2009-03-19 15:04:43 +01:00
|
|
|
tmp.removeAll(remove);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-02 21:00:09 +01:00
|
|
|
visitProBlock(pro);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
m_lineNo = pro->lineNumber();
|
2009-07-28 18:54:03 +02:00
|
|
|
|
2009-07-22 17:46:25 +02:00
|
|
|
if (m_profileStack.count() == 1) {
|
2009-07-22 11:03:01 +02:00
|
|
|
if (m_parsePreAndPostFiles) {
|
|
|
|
|
evaluateFeatureFile(QLatin1String("default_post.prf"));
|
|
|
|
|
|
|
|
|
|
QSet<QString> processed;
|
|
|
|
|
forever {
|
|
|
|
|
bool finished = true;
|
2010-02-08 17:15:44 +01:00
|
|
|
QStringList configs = valuesDirect(statics.strCONFIG);
|
2009-07-22 11:03:01 +02:00
|
|
|
for (int i = configs.size() - 1; i >= 0; --i) {
|
2009-08-04 20:51:49 +02:00
|
|
|
const QString config = configs.at(i).toLower();
|
2009-07-22 11:03:01 +02:00
|
|
|
if (!processed.contains(config)) {
|
|
|
|
|
processed.insert(config);
|
|
|
|
|
if (evaluateFeatureFile(config)) {
|
|
|
|
|
finished = false;
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-22 11:03:01 +02:00
|
|
|
if (finished)
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-22 17:46:25 +02:00
|
|
|
m_profileStack.pop();
|
|
|
|
|
|
2010-02-03 18:16:46 +01:00
|
|
|
return ProItem::ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-05-18 17:46:30 +02:00
|
|
|
ProItem::ProItemReturn ProFileEvaluator::Private::visitProFunction(ProFunction *func)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-05-14 14:30:08 +02:00
|
|
|
// Make sure that called subblocks don't inherit & destroy the state
|
|
|
|
|
bool invertThis = m_invertNext;
|
|
|
|
|
m_invertNext = false;
|
2009-08-14 14:36:34 +02:00
|
|
|
if (!m_skipLevel) {
|
|
|
|
|
m_hadCondition = true;
|
2009-05-14 14:35:37 +02:00
|
|
|
m_sts.prevCondition = false;
|
2009-08-14 14:36:34 +02:00
|
|
|
}
|
2009-05-14 14:35:37 +02:00
|
|
|
if (m_cumulative || !m_sts.condition) {
|
2008-12-12 18:10:42 +01:00
|
|
|
QString text = func->text();
|
|
|
|
|
int lparen = text.indexOf(QLatin1Char('('));
|
|
|
|
|
int rparen = text.lastIndexOf(QLatin1Char(')'));
|
2009-01-08 10:46:00 +01:00
|
|
|
Q_ASSERT(lparen < rparen);
|
2008-12-12 18:10:42 +01:00
|
|
|
QString arguments = text.mid(lparen + 1, rparen - lparen - 1);
|
|
|
|
|
QString funcName = text.left(lparen);
|
|
|
|
|
m_lineNo = func->lineNumber();
|
2009-05-18 17:46:30 +02:00
|
|
|
ProItem::ProItemReturn result = evaluateConditionalFunction(funcName.trimmed(), arguments);
|
|
|
|
|
if (result != ProItem::ReturnFalse && result != ProItem::ReturnTrue)
|
|
|
|
|
return result;
|
|
|
|
|
if (!m_skipLevel && ((result == ProItem::ReturnTrue) ^ invertThis))
|
2009-05-14 14:35:37 +02:00
|
|
|
m_sts.condition = true;
|
2008-12-12 18:10:42 +01:00
|
|
|
}
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-07-23 18:36:59 +02:00
|
|
|
QStringList ProFileEvaluator::Private::qmakeMkspecPaths() const
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
QStringList ret;
|
2009-08-04 16:16:27 +02:00
|
|
|
const QString concat = QLatin1String("/mkspecs");
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
QByteArray qmakepath = qgetenv("QMAKEPATH");
|
2009-08-04 16:16:27 +02:00
|
|
|
if (!qmakepath.isEmpty())
|
|
|
|
|
foreach (const QString &it, QString::fromLocal8Bit(qmakepath).split(m_option->dirlist_sep))
|
|
|
|
|
ret << QDir::cleanPath(it) + concat;
|
|
|
|
|
|
2010-01-21 18:24:46 +01:00
|
|
|
QString builtIn = propertyValue(QLatin1String("QT_INSTALL_DATA")) + concat;
|
|
|
|
|
if (!ret.contains(builtIn))
|
|
|
|
|
ret << builtIn;
|
2009-07-23 16:34:30 +02:00
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 18:36:59 +02:00
|
|
|
QStringList ProFileEvaluator::Private::qmakeFeaturePaths() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-07-31 16:47:18 +02:00
|
|
|
QString mkspecs_concat = QLatin1String("/mkspecs");
|
|
|
|
|
QString features_concat = QLatin1String("/features");
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList concat;
|
2009-07-31 16:47:18 +02:00
|
|
|
switch (m_option->target_mode) {
|
2009-12-07 20:32:36 +01:00
|
|
|
case ProFileOption::TARG_MACX_MODE:
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << QLatin1String("/features/mac");
|
|
|
|
|
concat << QLatin1String("/features/macx");
|
|
|
|
|
concat << QLatin1String("/features/unix");
|
|
|
|
|
break;
|
2009-12-07 20:32:36 +01:00
|
|
|
case ProFileOption::TARG_UNIX_MODE:
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << QLatin1String("/features/unix");
|
|
|
|
|
break;
|
2009-12-07 20:32:36 +01:00
|
|
|
case ProFileOption::TARG_WIN_MODE:
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << QLatin1String("/features/win32");
|
|
|
|
|
break;
|
2009-12-07 20:32:36 +01:00
|
|
|
case ProFileOption::TARG_MAC9_MODE:
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << QLatin1String("/features/mac");
|
|
|
|
|
concat << QLatin1String("/features/mac9");
|
|
|
|
|
break;
|
2009-12-07 20:32:36 +01:00
|
|
|
case ProFileOption::TARG_QNX6_MODE:
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << QLatin1String("/features/qnx6");
|
|
|
|
|
concat << QLatin1String("/features/unix");
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-07-31 16:47:18 +02:00
|
|
|
concat << features_concat;
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList feature_roots;
|
2009-07-31 16:47:18 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QByteArray mkspec_path = qgetenv("QMAKEFEATURES");
|
2009-08-04 16:16:27 +02:00
|
|
|
if (!mkspec_path.isEmpty())
|
|
|
|
|
foreach (const QString &f, QString::fromLocal8Bit(mkspec_path).split(m_option->dirlist_sep))
|
2010-02-05 19:24:33 +01:00
|
|
|
feature_roots += resolvePath(f);
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2009-08-04 15:56:26 +02:00
|
|
|
feature_roots += propertyValue(QLatin1String("QMAKEFEATURES"), false).split(
|
2009-08-04 16:16:27 +02:00
|
|
|
m_option->dirlist_sep, QString::SkipEmptyParts);
|
|
|
|
|
|
|
|
|
|
if (!m_option->cachefile.isEmpty()) {
|
2010-02-05 19:24:33 +01:00
|
|
|
QString path = m_option->cachefile.left(m_option->cachefile.lastIndexOf((ushort)'/'));
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &concat_it, concat)
|
|
|
|
|
feature_roots << (path + concat_it);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray qmakepath = qgetenv("QMAKEPATH");
|
|
|
|
|
if (!qmakepath.isNull()) {
|
2009-07-23 18:36:59 +02:00
|
|
|
const QStringList lst = QString::fromLocal8Bit(qmakepath).split(m_option->dirlist_sep);
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &item, lst) {
|
2010-02-05 19:24:33 +01:00
|
|
|
QString citem = resolvePath(item);
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &concat_it, concat)
|
2009-08-04 16:16:27 +02:00
|
|
|
feature_roots << (citem + mkspecs_concat + concat_it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_option->qmakespec.isEmpty()) {
|
2010-02-05 19:24:33 +01:00
|
|
|
QString qmakespec = resolvePath(m_option->qmakespec);
|
|
|
|
|
feature_roots << (qmakespec + features_concat);
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2010-02-05 19:24:33 +01:00
|
|
|
QDir specdir(qmakespec);
|
2009-08-04 16:16:27 +02:00
|
|
|
while (!specdir.isRoot()) {
|
|
|
|
|
if (!specdir.cdUp() || specdir.isRoot())
|
|
|
|
|
break;
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(specdir.path() + features_concat)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
foreach (const QString &concat_it, concat)
|
|
|
|
|
feature_roots << (specdir.path() + concat_it);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &concat_it, concat)
|
|
|
|
|
feature_roots << (propertyValue(QLatin1String("QT_INSTALL_PREFIX")) +
|
|
|
|
|
mkspecs_concat + concat_it);
|
|
|
|
|
foreach (const QString &concat_it, concat)
|
|
|
|
|
feature_roots << (propertyValue(QLatin1String("QT_INSTALL_DATA")) +
|
|
|
|
|
mkspecs_concat + concat_it);
|
2009-08-04 16:16:27 +02:00
|
|
|
|
|
|
|
|
for (int i = 0; i < feature_roots.count(); ++i)
|
|
|
|
|
if (!feature_roots.at(i).endsWith((ushort)'/'))
|
|
|
|
|
feature_roots[i].append((ushort)'/');
|
|
|
|
|
|
2010-01-21 18:24:46 +01:00
|
|
|
feature_roots.removeDuplicates();
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
return feature_roots;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-04 15:56:26 +02:00
|
|
|
QString ProFileEvaluator::Private::propertyValue(const QString &name, bool complain) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-08-04 16:12:11 +02:00
|
|
|
if (m_option->properties.contains(name))
|
|
|
|
|
return m_option->properties.value(name);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (name == QLatin1String("QMAKE_MKSPECS"))
|
2009-07-23 18:36:59 +02:00
|
|
|
return qmakeMkspecPaths().join(m_option->dirlist_sep);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (name == QLatin1String("QMAKE_VERSION"))
|
|
|
|
|
return QLatin1String("1.0"); //### FIXME
|
2009-08-04 15:56:26 +02:00
|
|
|
if (complain)
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("Querying unknown property %1").arg(name));
|
2009-08-04 15:21:40 +02:00
|
|
|
return QString();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProFile *ProFileEvaluator::Private::currentProFile() const
|
|
|
|
|
{
|
|
|
|
|
if (m_profileStack.count() > 0)
|
|
|
|
|
return m_profileStack.top();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ProFileEvaluator::Private::currentFileName() const
|
|
|
|
|
{
|
|
|
|
|
ProFile *pro = currentProFile();
|
|
|
|
|
if (pro)
|
|
|
|
|
return pro->fileName();
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-19 21:19:38 +01:00
|
|
|
QString ProFileEvaluator::Private::currentDirectory() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
ProFile *cur = m_profileStack.top();
|
2008-12-19 21:35:10 +01:00
|
|
|
return cur->directoryName();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-05-19 19:00:06 +02:00
|
|
|
void ProFileEvaluator::Private::doVariableReplace(QString *str)
|
|
|
|
|
{
|
2010-02-08 16:47:25 +01:00
|
|
|
*str = expandVariableReferences(*str).join(statics.field_sep);
|
2009-05-19 19:00:06 +02:00
|
|
|
}
|
|
|
|
|
|
2010-01-14 18:02:22 +01:00
|
|
|
// Be fast even for debug builds
|
|
|
|
|
#ifdef __GNUC__
|
|
|
|
|
# define ALWAYS_INLINE __attribute__((always_inline))
|
|
|
|
|
#else
|
|
|
|
|
# define ALWAYS_INLINE
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// The (QChar*)current->constData() constructs below avoid pointless detach() calls
|
|
|
|
|
static inline void ALWAYS_INLINE appendChar(ushort unicode,
|
|
|
|
|
QString *current, QChar **ptr, QString *pending)
|
|
|
|
|
{
|
|
|
|
|
if (!pending->isEmpty()) {
|
|
|
|
|
int len = pending->size();
|
|
|
|
|
current->resize(current->size() + len);
|
|
|
|
|
::memcpy((QChar*)current->constData(), pending->constData(), len * 2);
|
|
|
|
|
pending->clear();
|
|
|
|
|
*ptr = (QChar*)current->constData() + len;
|
|
|
|
|
}
|
|
|
|
|
*(*ptr)++ = QChar(unicode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void appendString(const QString &string,
|
|
|
|
|
QString *current, QChar **ptr, QString *pending)
|
|
|
|
|
{
|
|
|
|
|
if (string.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
QChar *uc = (QChar*)current->constData();
|
|
|
|
|
int len;
|
|
|
|
|
if (*ptr != uc) {
|
|
|
|
|
len = *ptr - uc;
|
|
|
|
|
current->resize(current->size() + string.size());
|
|
|
|
|
} else if (!pending->isEmpty()) {
|
|
|
|
|
len = pending->size();
|
|
|
|
|
current->resize(current->size() + len + string.size());
|
|
|
|
|
::memcpy((QChar*)current->constData(), pending->constData(), len * 2);
|
|
|
|
|
pending->clear();
|
|
|
|
|
} else {
|
|
|
|
|
*pending = string;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*ptr = (QChar*)current->constData() + len;
|
|
|
|
|
::memcpy(*ptr, string.data(), string.size() * 2);
|
|
|
|
|
*ptr += string.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void flushCurrent(QStringList *ret,
|
|
|
|
|
QString *current, QChar **ptr, QString *pending)
|
|
|
|
|
{
|
|
|
|
|
QChar *uc = (QChar*)current->constData();
|
|
|
|
|
int len = *ptr - uc;
|
|
|
|
|
if (len) {
|
|
|
|
|
ret->append(QString(uc, len));
|
|
|
|
|
*ptr = uc;
|
|
|
|
|
} else if (!pending->isEmpty()) {
|
|
|
|
|
ret->append(*pending);
|
|
|
|
|
pending->clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void flushFinal(QStringList *ret,
|
|
|
|
|
const QString ¤t, const QChar *ptr, const QString &pending,
|
|
|
|
|
const QString &str, bool replaced)
|
|
|
|
|
{
|
|
|
|
|
int len = ptr - current.data();
|
|
|
|
|
if (len) {
|
|
|
|
|
if (!replaced && len == str.size())
|
|
|
|
|
ret->append(str);
|
|
|
|
|
else
|
|
|
|
|
ret->append(QString(current.data(), len));
|
|
|
|
|
} else if (!pending.isEmpty()) {
|
|
|
|
|
ret->append(pending);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-14 17:43:02 +01:00
|
|
|
QStringList ProFileEvaluator::Private::expandVariableReferences(
|
2010-01-19 12:31:39 +01:00
|
|
|
const QString &str, bool do_semicolon, int *pos)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
QStringList ret;
|
2009-03-11 17:47:43 +01:00
|
|
|
// if (ok)
|
|
|
|
|
// *ok = true;
|
2008-12-02 12:01:29 +01:00
|
|
|
if (str.isEmpty())
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
const ushort LSQUARE = '[';
|
|
|
|
|
const ushort RSQUARE = ']';
|
|
|
|
|
const ushort LCURLY = '{';
|
|
|
|
|
const ushort RCURLY = '}';
|
|
|
|
|
const ushort LPAREN = '(';
|
|
|
|
|
const ushort RPAREN = ')';
|
|
|
|
|
const ushort DOLLAR = '$';
|
|
|
|
|
const ushort BACKSLASH = '\\';
|
|
|
|
|
const ushort UNDERSCORE = '_';
|
|
|
|
|
const ushort DOT = '.';
|
|
|
|
|
const ushort SPACE = ' ';
|
|
|
|
|
const ushort TAB = '\t';
|
2010-01-14 17:43:02 +01:00
|
|
|
const ushort SEMICOLON = ';';
|
2010-01-19 12:31:39 +01:00
|
|
|
const ushort COMMA = ',';
|
2009-03-11 17:47:43 +01:00
|
|
|
const ushort SINGLEQUOTE = '\'';
|
|
|
|
|
const ushort DOUBLEQUOTE = '"';
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-19 12:31:39 +01:00
|
|
|
ushort unicode, quote = 0, parens = 0;
|
2010-01-22 16:20:44 +01:00
|
|
|
const ushort *str_data = (const ushort *)str.data();
|
2008-12-02 12:01:29 +01:00
|
|
|
const int str_len = str.length();
|
|
|
|
|
|
|
|
|
|
QString var, args;
|
|
|
|
|
|
2010-01-14 18:02:22 +01:00
|
|
|
bool replaced = false;
|
|
|
|
|
QString current; // Buffer for successively assembled string segments
|
|
|
|
|
current.resize(str.size());
|
|
|
|
|
QChar *ptr = current.data();
|
|
|
|
|
QString pending; // Buffer for string segments from variables
|
|
|
|
|
// Only one of the above buffers can be filled at a given time.
|
2010-01-19 12:31:39 +01:00
|
|
|
for (int i = pos ? *pos : 0; i < str_len; ++i) {
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[i];
|
2010-01-14 18:02:22 +01:00
|
|
|
if (unicode == DOLLAR) {
|
2010-01-22 16:20:44 +01:00
|
|
|
if (str_len > i+2 && str_data[i+1] == DOLLAR) {
|
2010-01-14 18:02:22 +01:00
|
|
|
++i;
|
|
|
|
|
ushort term = 0;
|
2008-12-02 12:01:29 +01:00
|
|
|
enum { VAR, ENVIRON, FUNCTION, PROPERTY } var_type = VAR;
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[++i];
|
2009-03-11 17:47:43 +01:00
|
|
|
if (unicode == LSQUARE) {
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[++i];
|
2008-12-02 12:01:29 +01:00
|
|
|
term = RSQUARE;
|
|
|
|
|
var_type = PROPERTY;
|
2009-03-11 17:47:43 +01:00
|
|
|
} else if (unicode == LCURLY) {
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[++i];
|
2008-12-02 12:01:29 +01:00
|
|
|
var_type = VAR;
|
|
|
|
|
term = RCURLY;
|
2009-03-11 17:47:43 +01:00
|
|
|
} else if (unicode == LPAREN) {
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[++i];
|
2008-12-02 12:01:29 +01:00
|
|
|
var_type = ENVIRON;
|
|
|
|
|
term = RPAREN;
|
|
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
int name_start = i;
|
2009-03-11 17:47:43 +01:00
|
|
|
forever {
|
|
|
|
|
if (!(unicode & (0xFF<<8)) &&
|
|
|
|
|
unicode != DOT && unicode != UNDERSCORE &&
|
|
|
|
|
//unicode != SINGLEQUOTE && unicode != DOUBLEQUOTE &&
|
|
|
|
|
(unicode < 'a' || unicode > 'z') && (unicode < 'A' || unicode > 'Z') &&
|
|
|
|
|
(unicode < '0' || unicode > '9'))
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
if (++i == str_len)
|
|
|
|
|
break;
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[i];
|
2009-03-11 17:47:43 +01:00
|
|
|
// at this point, i points to either the 'term' or 'next' character (which is in unicode)
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-01-22 16:20:44 +01:00
|
|
|
var = QString::fromRawData((QChar*)str_data + name_start, i - name_start);
|
2009-03-11 17:47:43 +01:00
|
|
|
if (var_type == VAR && unicode == LPAREN) {
|
2008-12-02 12:01:29 +01:00
|
|
|
var_type = FUNCTION;
|
2010-01-14 18:02:22 +01:00
|
|
|
name_start = i + 1;
|
2008-12-02 12:01:29 +01:00
|
|
|
int depth = 0;
|
2009-03-11 17:47:43 +01:00
|
|
|
forever {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (++i == str_len)
|
|
|
|
|
break;
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[i];
|
2009-03-11 17:47:43 +01:00
|
|
|
if (unicode == LPAREN) {
|
2008-12-02 12:01:29 +01:00
|
|
|
depth++;
|
2009-03-11 17:47:43 +01:00
|
|
|
} else if (unicode == RPAREN) {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!depth)
|
|
|
|
|
break;
|
|
|
|
|
--depth;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-01-22 16:20:44 +01:00
|
|
|
args = QString((QChar*)str_data + name_start, i - name_start);
|
2009-03-11 17:47:43 +01:00
|
|
|
if (++i < str_len)
|
2010-01-22 16:20:44 +01:00
|
|
|
unicode = str_data[i];
|
2008-12-02 12:01:29 +01:00
|
|
|
else
|
2009-03-11 17:47:43 +01:00
|
|
|
unicode = 0;
|
|
|
|
|
// at this point i is pointing to the 'next' character (which is in unicode)
|
|
|
|
|
// this might actually be a term character since you can do $${func()}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
if (term) {
|
2009-03-11 17:47:43 +01:00
|
|
|
if (unicode != term) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("Missing %1 terminator [found %2]")
|
2009-03-11 17:47:43 +01:00
|
|
|
.arg(QChar(term))
|
|
|
|
|
.arg(unicode ? QString(unicode) : QString::fromLatin1(("end-of-line"))));
|
|
|
|
|
// if (ok)
|
|
|
|
|
// *ok = false;
|
2010-01-19 12:31:39 +01:00
|
|
|
if (pos)
|
|
|
|
|
*pos = str_len;
|
2008-12-02 12:01:29 +01:00
|
|
|
return QStringList();
|
|
|
|
|
}
|
2009-03-11 17:47:43 +01:00
|
|
|
} else {
|
|
|
|
|
// move the 'cursor' back to the last char of the thing we were looking at
|
|
|
|
|
--i;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList replacement;
|
|
|
|
|
if (var_type == ENVIRON) {
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
replacement = split_value_list(QString::fromLocal8Bit(qgetenv(var.toLocal8Bit().constData())));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (var_type == PROPERTY) {
|
|
|
|
|
replacement << propertyValue(var);
|
|
|
|
|
} else if (var_type == FUNCTION) {
|
|
|
|
|
replacement << evaluateExpandFunction(var, args);
|
|
|
|
|
} else if (var_type == VAR) {
|
2010-02-11 16:33:16 +01:00
|
|
|
replacement = values(map(var));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
if (!replacement.isEmpty()) {
|
2009-03-11 17:47:43 +01:00
|
|
|
if (quote) {
|
2010-02-08 16:47:25 +01:00
|
|
|
appendString(replacement.join(statics.field_sep),
|
2010-01-14 18:02:22 +01:00
|
|
|
¤t, &ptr, &pending);
|
2009-03-11 17:47:43 +01:00
|
|
|
} else {
|
2010-04-06 19:56:58 +02:00
|
|
|
appendString(replacement.at(0), ¤t, &ptr, &pending);
|
2010-01-14 18:02:22 +01:00
|
|
|
if (replacement.size() > 1) {
|
|
|
|
|
flushCurrent(&ret, ¤t, &ptr, &pending);
|
2010-04-06 19:56:58 +02:00
|
|
|
int j = 1;
|
2010-01-14 18:02:22 +01:00
|
|
|
if (replacement.size() > 2) {
|
|
|
|
|
// FIXME: ret.reserve(ret.size() + replacement.size() - 2);
|
2010-04-06 19:56:58 +02:00
|
|
|
for (; j < replacement.size() - 1; ++j)
|
|
|
|
|
ret << replacement.at(j);
|
2010-01-14 18:02:22 +01:00
|
|
|
}
|
2010-04-06 19:56:58 +02:00
|
|
|
pending = replacement.at(j);
|
2009-03-11 17:47:43 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
replaced = true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
continue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-03-11 17:47:43 +01:00
|
|
|
} else if (unicode == BACKSLASH) {
|
2010-01-14 18:02:22 +01:00
|
|
|
static const char symbols[] = "[]{}()$\\'\"";
|
2010-01-22 16:20:44 +01:00
|
|
|
ushort unicode2 = str_data[i+1];
|
2010-01-14 18:02:22 +01:00
|
|
|
if (!(unicode2 & 0xff00) && strchr(symbols, unicode2)) {
|
|
|
|
|
unicode = unicode2;
|
|
|
|
|
++i;
|
2009-03-11 17:47:43 +01:00
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
} else if (quote) {
|
|
|
|
|
if (unicode == quote) {
|
|
|
|
|
quote = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) {
|
|
|
|
|
quote = unicode;
|
|
|
|
|
continue;
|
|
|
|
|
} else if ((do_semicolon && unicode == SEMICOLON) ||
|
|
|
|
|
unicode == SPACE || unicode == TAB) {
|
|
|
|
|
flushCurrent(&ret, ¤t, &ptr, &pending);
|
|
|
|
|
continue;
|
2010-01-19 12:31:39 +01:00
|
|
|
} else if (pos) {
|
|
|
|
|
if (unicode == LPAREN) {
|
|
|
|
|
++parens;
|
|
|
|
|
} else if (unicode == RPAREN) {
|
|
|
|
|
--parens;
|
|
|
|
|
} else if (!parens && unicode == COMMA) {
|
|
|
|
|
*pos = i + 1;
|
|
|
|
|
flushFinal(&ret, current, ptr, pending, str, replaced);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2009-03-11 17:47:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-01-14 18:02:22 +01:00
|
|
|
appendChar(unicode, ¤t, &ptr, &pending);
|
2010-01-14 17:43:02 +01:00
|
|
|
}
|
2010-01-19 12:31:39 +01:00
|
|
|
if (pos)
|
|
|
|
|
*pos = str_len;
|
2010-01-14 18:02:22 +01:00
|
|
|
flushFinal(&ret, current, ptr, pending, str, replaced);
|
2008-12-02 12:01:29 +01:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProFileEvaluator::Private::isActiveConfig(const QString &config, bool regex)
|
|
|
|
|
{
|
|
|
|
|
// magic types for easy flipping
|
2010-02-08 17:15:44 +01:00
|
|
|
if (config == statics.strtrue)
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
2010-02-08 17:15:44 +01:00
|
|
|
if (config == statics.strfalse)
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// mkspecs
|
2009-07-23 18:36:59 +02:00
|
|
|
if ((m_option->target_mode == m_option->TARG_MACX_MODE
|
|
|
|
|
|| m_option->target_mode == m_option->TARG_QNX6_MODE
|
|
|
|
|
|| m_option->target_mode == m_option->TARG_UNIX_MODE)
|
2010-02-08 17:15:44 +01:00
|
|
|
&& config == statics.strunix)
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
2010-02-08 17:15:44 +01:00
|
|
|
if (m_option->target_mode == m_option->TARG_MACX_MODE && config == statics.strmacx)
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
2010-02-08 17:15:44 +01:00
|
|
|
if (m_option->target_mode == m_option->TARG_QNX6_MODE && config == statics.strqnx6)
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
2010-02-08 17:15:44 +01:00
|
|
|
if (m_option->target_mode == m_option->TARG_MAC9_MODE && config == statics.strmac9)
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
2009-07-23 18:36:59 +02:00
|
|
|
if ((m_option->target_mode == m_option->TARG_MAC9_MODE
|
|
|
|
|
|| m_option->target_mode == m_option->TARG_MACX_MODE)
|
2010-02-08 17:15:44 +01:00
|
|
|
&& config == statics.strmac)
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
2010-02-08 17:15:44 +01:00
|
|
|
if (m_option->target_mode == m_option->TARG_WIN_MODE && config == statics.strwin32)
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
|
|
|
|
|
2010-01-19 18:36:03 +01:00
|
|
|
if (regex && (config.contains(QLatin1Char('*')) || config.contains(QLatin1Char('?')))) {
|
2009-07-02 11:05:01 +10:00
|
|
|
QRegExp re(config, Qt::CaseSensitive, QRegExp::Wildcard);
|
|
|
|
|
|
2010-02-10 15:35:57 +01:00
|
|
|
if (re.exactMatch(m_option->qmakespec_name))
|
2009-07-02 11:05:01 +10:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// CONFIG variable
|
2010-02-09 20:38:21 +01:00
|
|
|
foreach (const QString &configValue, valuesDirect(statics.strCONFIG)) {
|
2009-07-02 11:05:01 +10:00
|
|
|
if (re.exactMatch(configValue))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// mkspecs
|
2010-02-10 15:35:57 +01:00
|
|
|
if (m_option->qmakespec_name == config)
|
2009-07-02 11:05:01 +10:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// CONFIG variable
|
2010-02-09 20:38:21 +01:00
|
|
|
foreach (const QString &configValue, valuesDirect(statics.strCONFIG)) {
|
2009-07-02 11:05:01 +10:00
|
|
|
if (configValue == config)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-14 17:36:07 +02:00
|
|
|
QList<QStringList> ProFileEvaluator::Private::prepareFunctionArgs(const QString &arguments)
|
|
|
|
|
{
|
|
|
|
|
QList<QStringList> args_list;
|
2010-01-19 12:31:39 +01:00
|
|
|
for (int pos = 0; pos < arguments.length(); )
|
|
|
|
|
args_list << expandVariableReferences(arguments, false, &pos);
|
2009-08-14 17:36:07 +02:00
|
|
|
return args_list;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-18 17:46:30 +02:00
|
|
|
QStringList ProFileEvaluator::Private::evaluateFunction(
|
2009-08-14 17:36:07 +02:00
|
|
|
ProBlock *funcPtr, const QList<QStringList> &argumentsList, bool *ok)
|
2009-05-18 17:46:30 +02:00
|
|
|
{
|
|
|
|
|
bool oki;
|
|
|
|
|
QStringList ret;
|
|
|
|
|
|
|
|
|
|
if (m_valuemapStack.count() >= 100) {
|
2009-08-12 13:00:21 +02:00
|
|
|
errorMessage(format("ran into infinite recursion (depth > 100)."));
|
2009-06-03 19:04:10 +02:00
|
|
|
oki = false;
|
2009-05-18 17:46:30 +02:00
|
|
|
} else {
|
|
|
|
|
State sts = m_sts;
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.push(QHash<QString, QStringList>());
|
2009-05-18 17:46:30 +02:00
|
|
|
|
|
|
|
|
QStringList args;
|
|
|
|
|
for (int i = 0; i < argumentsList.count(); ++i) {
|
2009-08-14 17:36:07 +02:00
|
|
|
args += argumentsList[i];
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top()[QString::number(i+1)] = argumentsList[i];
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top()[statics.strARGS] = args;
|
2010-02-02 21:00:09 +01:00
|
|
|
oki = (visitProBlock(funcPtr) != ProItem::ReturnFalse); // True || Return
|
2009-05-18 17:46:30 +02:00
|
|
|
ret = m_returnValue;
|
|
|
|
|
m_returnValue.clear();
|
|
|
|
|
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.pop();
|
2009-05-18 17:46:30 +02:00
|
|
|
m_sts = sts;
|
|
|
|
|
}
|
|
|
|
|
if (ok)
|
|
|
|
|
*ok = oki;
|
|
|
|
|
if (oki)
|
|
|
|
|
return ret;
|
|
|
|
|
return QStringList();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments)
|
|
|
|
|
{
|
2009-08-14 17:36:07 +02:00
|
|
|
QList<QStringList> args_list = prepareFunctionArgs(arguments);
|
2009-03-17 17:12:29 +01:00
|
|
|
|
2009-08-10 17:27:07 +02:00
|
|
|
if (ProBlock *funcPtr = m_functionDefs.replaceFunctions.value(func, 0))
|
2009-08-14 17:36:07 +02:00
|
|
|
return evaluateFunction(funcPtr, args_list, 0);
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2009-08-14 17:36:07 +02:00
|
|
|
QStringList args; //why don't the builtin functions just use args_list? --Sam
|
|
|
|
|
foreach (const QStringList &arg, args_list)
|
2010-02-08 16:47:25 +01:00
|
|
|
args += arg.join(statics.field_sep);
|
|
|
|
|
|
|
|
|
|
ExpandFunc func_t = ExpandFunc(statics.expands.value(func.toLower()));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
QStringList ret;
|
|
|
|
|
|
|
|
|
|
switch (func_t) {
|
|
|
|
|
case E_BASENAME:
|
|
|
|
|
case E_DIRNAME:
|
|
|
|
|
case E_SECTION: {
|
|
|
|
|
bool regexp = false;
|
|
|
|
|
QString sep, var;
|
|
|
|
|
int beg = 0;
|
|
|
|
|
int end = -1;
|
|
|
|
|
if (func_t == E_SECTION) {
|
|
|
|
|
if (args.count() != 3 && args.count() != 4) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("%1(var) section(var, sep, begin, end) "
|
2008-12-04 19:16:48 +01:00
|
|
|
"requires three or four arguments.").arg(func));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
|
var = args[0];
|
|
|
|
|
sep = args[1];
|
|
|
|
|
beg = args[2].toInt();
|
|
|
|
|
if (args.count() == 4)
|
|
|
|
|
end = args[3].toInt();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("%1(var) requires one argument.").arg(func));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
|
var = args[0];
|
|
|
|
|
regexp = true;
|
|
|
|
|
sep = QLatin1String("[\\\\/]");
|
|
|
|
|
if (func_t == E_DIRNAME)
|
|
|
|
|
end = -2;
|
|
|
|
|
else
|
|
|
|
|
beg = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!var.isNull()) {
|
2010-01-19 18:36:03 +01:00
|
|
|
if (regexp) {
|
|
|
|
|
QRegExp sepRx(sep);
|
2010-02-11 16:33:16 +01:00
|
|
|
foreach (const QString &str, values(map(var)))
|
2010-01-19 18:36:03 +01:00
|
|
|
ret += str.section(sepRx, beg, end);
|
|
|
|
|
} else {
|
2010-02-11 16:33:16 +01:00
|
|
|
foreach (const QString &str, values(map(var)))
|
2008-12-02 12:01:29 +01:00
|
|
|
ret += str.section(sep, beg, end);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
case E_SPRINTF:
|
|
|
|
|
if(args.count() < 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("sprintf(format, ...) requires at least one argument"));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
|
|
|
|
QString tmp = args.at(0);
|
|
|
|
|
for (int i = 1; i < args.count(); ++i)
|
|
|
|
|
tmp = tmp.arg(args.at(i));
|
|
|
|
|
ret = split_value_list(tmp);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
case E_JOIN: {
|
|
|
|
|
if (args.count() < 1 || args.count() > 4) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("join(var, glue, before, after) requires one to four arguments."));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
|
QString glue, before, after;
|
|
|
|
|
if (args.count() >= 2)
|
|
|
|
|
glue = args[1];
|
|
|
|
|
if (args.count() >= 3)
|
|
|
|
|
before = args[2];
|
|
|
|
|
if (args.count() == 4)
|
|
|
|
|
after = args[3];
|
2010-02-11 16:33:16 +01:00
|
|
|
const QStringList &var = values(map(args.first()));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!var.isEmpty())
|
|
|
|
|
ret.append(before + var.join(glue) + after);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-08-12 13:42:29 +02:00
|
|
|
case E_SPLIT:
|
2008-12-04 19:16:48 +01:00
|
|
|
if (args.count() != 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("split(var, sep) requires one or two arguments"));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-02-08 16:47:25 +01:00
|
|
|
const QString &sep = (args.count() == 2) ? args[1] : statics.field_sep;
|
2010-02-11 16:33:16 +01:00
|
|
|
foreach (const QString &var, values(map(args.first())))
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &splt, var.split(sep))
|
|
|
|
|
ret.append(splt);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2009-08-12 13:42:29 +02:00
|
|
|
case E_MEMBER:
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() < 1 || args.count() > 3) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("member(var, start, end) requires one to three arguments."));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
|
bool ok = true;
|
2010-02-11 16:33:16 +01:00
|
|
|
const QStringList &var = values(map(args.first()));
|
2008-12-02 12:01:29 +01:00
|
|
|
int start = 0, end = 0;
|
|
|
|
|
if (args.count() >= 2) {
|
|
|
|
|
QString start_str = args[1];
|
|
|
|
|
start = start_str.toInt(&ok);
|
|
|
|
|
if (!ok) {
|
|
|
|
|
if (args.count() == 2) {
|
2010-02-08 17:15:44 +01:00
|
|
|
int dotdot = start_str.indexOf(statics.strDotDot);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (dotdot != -1) {
|
|
|
|
|
start = start_str.left(dotdot).toInt(&ok);
|
|
|
|
|
if (ok)
|
|
|
|
|
end = start_str.mid(dotdot+2).toInt(&ok);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!ok)
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("member() argument 2 (start) '%2' invalid.")
|
2008-12-02 12:01:29 +01:00
|
|
|
.arg(start_str));
|
|
|
|
|
} else {
|
|
|
|
|
end = start;
|
|
|
|
|
if (args.count() == 3)
|
|
|
|
|
end = args[2].toInt(&ok);
|
|
|
|
|
if (!ok)
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("member() argument 3 (end) '%2' invalid.\n")
|
2008-12-02 12:01:29 +01:00
|
|
|
.arg(args[2]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ok) {
|
|
|
|
|
if (start < 0)
|
|
|
|
|
start += var.count();
|
|
|
|
|
if (end < 0)
|
|
|
|
|
end += var.count();
|
|
|
|
|
if (start < 0 || start >= var.count() || end < 0 || end >= var.count()) {
|
|
|
|
|
//nothing
|
|
|
|
|
} else if (start < end) {
|
|
|
|
|
for (int i = start; i <= end && var.count() >= i; i++)
|
|
|
|
|
ret.append(var[i]);
|
|
|
|
|
} else {
|
|
|
|
|
for (int i = start; i >= end && var.count() >= i && i >= 0; i--)
|
|
|
|
|
ret += var[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case E_FIRST:
|
2009-08-12 13:42:29 +02:00
|
|
|
case E_LAST:
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("%1(var) requires one argument.").arg(func));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-02-11 16:33:16 +01:00
|
|
|
const QStringList var = values(map(args.first()));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!var.isEmpty()) {
|
|
|
|
|
if (func_t == E_FIRST)
|
|
|
|
|
ret.append(var[0]);
|
|
|
|
|
else
|
|
|
|
|
ret.append(var.last());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2008-12-12 16:30:31 +01:00
|
|
|
case E_CAT:
|
|
|
|
|
if (args.count() < 1 || args.count() > 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("cat(file, singleline=true) requires one or two arguments."));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
|
|
|
|
QString file = args[0];
|
|
|
|
|
|
|
|
|
|
bool singleLine = true;
|
|
|
|
|
if (args.count() > 1)
|
2010-02-08 17:15:44 +01:00
|
|
|
singleLine = (!args[1].compare(statics.strtrue, Qt::CaseInsensitive));
|
2008-12-12 16:30:31 +01:00
|
|
|
|
2010-02-11 12:42:40 +01:00
|
|
|
QFile qfile(resolvePath(expandEnvVars(file)));
|
2008-12-12 16:30:31 +01:00
|
|
|
if (qfile.open(QIODevice::ReadOnly)) {
|
|
|
|
|
QTextStream stream(&qfile);
|
|
|
|
|
while (!stream.atEnd()) {
|
|
|
|
|
ret += split_value_list(stream.readLine().trimmed());
|
|
|
|
|
if (!singleLine)
|
|
|
|
|
ret += QLatin1String("\n");
|
|
|
|
|
}
|
|
|
|
|
qfile.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case E_FROMFILE:
|
|
|
|
|
if (args.count() != 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("fromfile(file, variable) requires two arguments."));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
2009-09-23 18:19:09 +02:00
|
|
|
QHash<QString, QStringList> vars;
|
2010-02-11 12:42:40 +01:00
|
|
|
if (evaluateFileInto(resolvePath(expandEnvVars(args.at(0))), &vars, 0))
|
2009-09-23 18:19:09 +02:00
|
|
|
ret = vars.value(args.at(1));
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
break;
|
2009-08-12 13:42:29 +02:00
|
|
|
case E_EVAL:
|
2008-12-12 16:30:31 +01:00
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("eval(variable) requires one argument"));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
2010-02-11 16:33:16 +01:00
|
|
|
ret += values(map(args.at(0)));
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
2009-08-12 13:42:29 +02:00
|
|
|
break;
|
2008-12-12 16:30:31 +01:00
|
|
|
case E_LIST: {
|
|
|
|
|
QString tmp;
|
2010-02-08 16:51:50 +01:00
|
|
|
tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", m_listCount++);
|
2008-12-12 16:30:31 +01:00
|
|
|
ret = QStringList(tmp);
|
|
|
|
|
QStringList lst;
|
|
|
|
|
foreach (const QString &arg, args)
|
|
|
|
|
lst += split_value_list(arg);
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.top()[tmp] = lst;
|
2008-12-12 16:30:31 +01:00
|
|
|
break; }
|
|
|
|
|
case E_FIND:
|
|
|
|
|
if (args.count() != 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("find(var, str) requires two arguments."));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
|
|
|
|
QRegExp regx(args[1]);
|
2010-02-11 16:33:16 +01:00
|
|
|
foreach (const QString &val, values(map(args.first())))
|
2008-12-12 16:30:31 +01:00
|
|
|
if (regx.indexIn(val) != -1)
|
|
|
|
|
ret += val;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case E_SYSTEM:
|
2009-03-02 19:58:54 +01:00
|
|
|
if (!m_skipLevel) {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() < 1 || args.count() > 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("system(execute) requires one or two arguments."));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
|
char buff[256];
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
FILE *proc = QT_POPEN(QString(QLatin1String("cd ")
|
2010-02-03 18:16:46 +01:00
|
|
|
+ IoUtils::shellQuote(currentDirectory())
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
+ QLatin1String(" && ") + args[0]).toLocal8Bit(), "r");
|
2008-12-02 12:01:29 +01:00
|
|
|
bool singleLine = true;
|
|
|
|
|
if (args.count() > 1)
|
2009-05-25 15:58:58 +02:00
|
|
|
singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive));
|
2008-12-02 12:01:29 +01:00
|
|
|
QString output;
|
|
|
|
|
while (proc && !feof(proc)) {
|
|
|
|
|
int read_in = int(fread(buff, 1, 255, proc));
|
|
|
|
|
if (!read_in)
|
|
|
|
|
break;
|
|
|
|
|
for (int i = 0; i < read_in; i++) {
|
|
|
|
|
if ((singleLine && buff[i] == '\n') || buff[i] == '\t')
|
|
|
|
|
buff[i] = ' ';
|
|
|
|
|
}
|
|
|
|
|
buff[read_in] = '\0';
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
output += QString::fromLocal8Bit(buff);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
ret += split_value_list(output);
|
2009-06-04 15:18:14 +02:00
|
|
|
if (proc)
|
|
|
|
|
QT_PCLOSE(proc);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
break;
|
|
|
|
|
case E_UNIQUE:
|
|
|
|
|
if(args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("unique(var) requires one argument."));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
2010-02-11 16:33:16 +01:00
|
|
|
ret = values(map(args.first()));
|
2010-02-04 10:47:55 +01:00
|
|
|
ret.removeDuplicates();
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
case E_QUOTE:
|
|
|
|
|
for (int i = 0; i < args.count(); ++i)
|
|
|
|
|
ret += QStringList(args.at(i));
|
|
|
|
|
break;
|
2008-12-12 16:30:31 +01:00
|
|
|
case E_ESCAPE_EXPAND:
|
|
|
|
|
for (int i = 0; i < args.size(); ++i) {
|
|
|
|
|
QChar *i_data = args[i].data();
|
|
|
|
|
int i_len = args[i].length();
|
|
|
|
|
for (int x = 0; x < i_len; ++x) {
|
|
|
|
|
if (*(i_data+x) == QLatin1Char('\\') && x < i_len-1) {
|
|
|
|
|
if (*(i_data+x+1) == QLatin1Char('\\')) {
|
|
|
|
|
++x;
|
|
|
|
|
} else {
|
|
|
|
|
struct {
|
|
|
|
|
char in, out;
|
|
|
|
|
} mapped_quotes[] = {
|
|
|
|
|
{ 'n', '\n' },
|
|
|
|
|
{ 't', '\t' },
|
|
|
|
|
{ 'r', '\r' },
|
|
|
|
|
{ 0, 0 }
|
|
|
|
|
};
|
|
|
|
|
for (int i = 0; mapped_quotes[i].in; ++i) {
|
|
|
|
|
if (*(i_data+x+1) == QLatin1Char(mapped_quotes[i].in)) {
|
|
|
|
|
*(i_data+x) = QLatin1Char(mapped_quotes[i].out);
|
|
|
|
|
if (x < i_len-2)
|
|
|
|
|
memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*sizeof(QChar));
|
|
|
|
|
--i_len;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ret.append(QString(i_data, i_len));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case E_RE_ESCAPE:
|
|
|
|
|
for (int i = 0; i < args.size(); ++i)
|
|
|
|
|
ret += QRegExp::escape(args[i]);
|
|
|
|
|
break;
|
|
|
|
|
case E_UPPER:
|
|
|
|
|
case E_LOWER:
|
|
|
|
|
for (int i = 0; i < args.count(); ++i)
|
|
|
|
|
if (func_t == E_UPPER)
|
|
|
|
|
ret += args[i].toUpper();
|
|
|
|
|
else
|
|
|
|
|
ret += args[i].toLower();
|
|
|
|
|
break;
|
|
|
|
|
case E_FILES:
|
|
|
|
|
if (args.count() != 1 && args.count() != 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("files(pattern, recursive=false) requires one or two arguments"));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
|
|
|
|
bool recursive = false;
|
|
|
|
|
if (args.count() == 2)
|
2010-02-08 17:15:44 +01:00
|
|
|
recursive = (!args[1].compare(statics.strtrue, Qt::CaseInsensitive) || args[1].toInt());
|
2008-12-12 16:30:31 +01:00
|
|
|
QStringList dirs;
|
2010-02-10 13:12:01 +01:00
|
|
|
QString r = fixPathToLocalOS(args[0]);
|
|
|
|
|
QString pfx;
|
|
|
|
|
if (IoUtils::isRelativePath(r)) {
|
|
|
|
|
pfx = currentDirectory();
|
|
|
|
|
if (!pfx.endsWith(QLatin1Char('/')))
|
|
|
|
|
pfx += QLatin1Char('/');
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
int slash = r.lastIndexOf(QDir::separator());
|
|
|
|
|
if (slash != -1) {
|
2010-02-10 16:20:16 +01:00
|
|
|
dirs.append(r.left(slash+1));
|
2008-12-12 16:30:31 +01:00
|
|
|
r = r.mid(slash+1);
|
|
|
|
|
} else {
|
2010-02-10 13:12:01 +01:00
|
|
|
dirs.append(QString());
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard);
|
|
|
|
|
for (int d = 0; d < dirs.count(); d++) {
|
|
|
|
|
QString dir = dirs[d];
|
2010-02-10 13:12:01 +01:00
|
|
|
QDir qdir(pfx + dir);
|
2008-12-12 16:30:31 +01:00
|
|
|
for (int i = 0; i < (int)qdir.count(); ++i) {
|
2010-02-08 17:15:44 +01:00
|
|
|
if (qdir[i] == statics.strDot || qdir[i] == statics.strDotDot)
|
2008-12-12 16:30:31 +01:00
|
|
|
continue;
|
|
|
|
|
QString fname = dir + qdir[i];
|
2010-02-10 13:12:01 +01:00
|
|
|
if (IoUtils::fileType(pfx + fname) == IoUtils::FileIsDir) {
|
2008-12-12 16:30:31 +01:00
|
|
|
if (recursive)
|
2010-02-10 16:20:16 +01:00
|
|
|
dirs.append(fname + QDir::separator());
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
if (regex.exactMatch(qdir[i]))
|
|
|
|
|
ret += fname;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case E_REPLACE:
|
|
|
|
|
if(args.count() != 3 ) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("replace(var, before, after) requires three arguments"));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
|
|
|
|
const QRegExp before(args[1]);
|
|
|
|
|
const QString after(args[2]);
|
2010-02-11 16:33:16 +01:00
|
|
|
foreach (QString val, values(map(args.first())))
|
2008-12-12 16:30:31 +01:00
|
|
|
ret += val.replace(before, after);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
case 0:
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("'%1' is not a recognized replace function").arg(func));
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("Function '%1' is not implemented").arg(func));
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-18 17:46:30 +02:00
|
|
|
ProItem::ProItemReturn ProFileEvaluator::Private::evaluateConditionalFunction(
|
2009-05-12 17:15:54 +02:00
|
|
|
const QString &function, const QString &arguments)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-08-14 17:36:07 +02:00
|
|
|
QList<QStringList> args_list = prepareFunctionArgs(arguments);
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2009-08-10 17:27:07 +02:00
|
|
|
if (ProBlock *funcPtr = m_functionDefs.testFunctions.value(function, 0)) {
|
2009-05-18 17:46:30 +02:00
|
|
|
bool ok;
|
2009-08-14 17:36:07 +02:00
|
|
|
QStringList ret = evaluateFunction(funcPtr, args_list, &ok);
|
2009-05-18 17:46:30 +02:00
|
|
|
if (ok) {
|
|
|
|
|
if (ret.isEmpty()) {
|
|
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
} else {
|
2010-02-08 17:15:44 +01:00
|
|
|
if (ret.first() != statics.strfalse) {
|
|
|
|
|
if (ret.first() == statics.strtrue) {
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
} else {
|
|
|
|
|
bool ok;
|
|
|
|
|
int val = ret.first().toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
if (val)
|
|
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
} else {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("Unexpected return value from test '%1': %2")
|
2009-05-18 17:46:30 +02:00
|
|
|
.arg(function).arg(ret.join(QLatin1String(" :: "))));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-14 17:36:07 +02:00
|
|
|
QStringList args; //why don't the builtin functions just use args_list? --Sam
|
|
|
|
|
foreach (const QStringList &arg, args_list)
|
2010-02-08 16:47:25 +01:00
|
|
|
args += arg.join(statics.field_sep);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-08 16:47:25 +01:00
|
|
|
TestFunc func_t = (TestFunc)statics.functions.value(function);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
switch (func_t) {
|
2009-05-18 17:46:30 +02:00
|
|
|
case T_DEFINE_TEST:
|
|
|
|
|
m_definingTest = true;
|
|
|
|
|
goto defineFunc;
|
|
|
|
|
case T_DEFINE_REPLACE:
|
|
|
|
|
m_definingTest = false;
|
|
|
|
|
defineFunc:
|
|
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("%s(function) requires one argument.").arg(function));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
|
|
|
|
m_definingFunc = args.first();
|
|
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
case T_DEFINED:
|
|
|
|
|
if (args.count() < 1 || args.count() > 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("defined(function, [\"test\"|\"replace\"])"
|
2009-05-18 17:46:30 +02:00
|
|
|
" requires one or two arguments."));
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
|
|
|
|
if (args.count() > 1) {
|
|
|
|
|
if (args[1] == QLatin1String("test"))
|
2009-08-10 17:27:07 +02:00
|
|
|
return returnBool(m_functionDefs.testFunctions.contains(args[0]));
|
2009-05-18 17:46:30 +02:00
|
|
|
else if (args[1] == QLatin1String("replace"))
|
2009-08-10 17:27:07 +02:00
|
|
|
return returnBool(m_functionDefs.replaceFunctions.contains(args[0]));
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("defined(function, type):"
|
2009-05-18 17:46:30 +02:00
|
|
|
" unexpected type [%1].\n").arg(args[1]));
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
2009-08-10 17:27:07 +02:00
|
|
|
return returnBool(m_functionDefs.replaceFunctions.contains(args[0])
|
|
|
|
|
|| m_functionDefs.testFunctions.contains(args[0]));
|
2009-05-18 17:46:30 +02:00
|
|
|
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_skipLevel || m_cumulative)
|
|
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
if (m_valuemapStack.isEmpty()) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("unexpected return()."));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
|
|
|
|
return ProItem::ReturnReturn;
|
2010-02-11 16:33:16 +01:00
|
|
|
case T_EXPORT: {
|
2009-05-18 17:46:30 +02:00
|
|
|
if (m_skipLevel && !m_cumulative)
|
|
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("export(variable) requires one argument."));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
2010-02-11 16:33:16 +01:00
|
|
|
const QString &var = map(args.at(0));
|
2010-02-09 20:38:21 +01:00
|
|
|
for (int i = m_valuemapStack.size(); --i > 0; ) {
|
2010-02-11 16:33:16 +01:00
|
|
|
QHash<QString, QStringList>::Iterator it = m_valuemapStack[i].find(var);
|
2010-02-09 20:38:21 +01:00
|
|
|
if (it != m_valuemapStack.at(i).end()) {
|
|
|
|
|
if (it->constBegin() == statics.fakeValue.constBegin()) {
|
|
|
|
|
// This is stupid, but qmake doesn't propagate deletions
|
2010-02-11 16:33:16 +01:00
|
|
|
m_valuemapStack[0][var] = QStringList();
|
2010-02-09 20:38:21 +01:00
|
|
|
} else {
|
2010-02-11 16:33:16 +01:00
|
|
|
m_valuemapStack[0][var] = *it;
|
2010-02-09 20:38:21 +01:00
|
|
|
}
|
|
|
|
|
m_valuemapStack[i].erase(it);
|
|
|
|
|
while (--i)
|
2010-02-11 16:33:16 +01:00
|
|
|
m_valuemapStack[i].remove(var);
|
2010-02-09 20:38:21 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnTrue;
|
2010-02-11 16:33:16 +01:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_INFILE:
|
2009-09-23 18:19:09 +02:00
|
|
|
if (args.count() < 2 || args.count() > 3) {
|
|
|
|
|
logMessage(format("infile(file, var, [values]) requires two or three arguments."));
|
|
|
|
|
} else {
|
|
|
|
|
QHash<QString, QStringList> vars;
|
2010-02-11 12:42:40 +01:00
|
|
|
if (!evaluateFileInto(resolvePath(expandEnvVars(args.at(0))), &vars, 0))
|
2009-09-23 18:19:09 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
if (args.count() == 2)
|
|
|
|
|
return returnBool(vars.contains(args.at(1)));
|
2010-01-19 18:36:03 +01:00
|
|
|
QRegExp regx;
|
|
|
|
|
const QString &qry = args.at(2);
|
|
|
|
|
if (qry != QRegExp::escape(qry))
|
|
|
|
|
regx.setPattern(qry);
|
2009-09-23 18:19:09 +02:00
|
|
|
foreach (const QString &s, vars.value(args.at(1)))
|
2010-01-19 18:36:03 +01:00
|
|
|
if ((!regx.isEmpty() && regx.exactMatch(s)) || s == qry)
|
2009-09-23 18:19:09 +02:00
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
}
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
#if 0
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_REQUIRES:
|
2009-05-19 19:00:06 +02:00
|
|
|
#endif
|
2009-10-02 17:37:02 +02:00
|
|
|
case T_EVAL: {
|
2010-02-03 10:08:45 +01:00
|
|
|
ProBlock *pro = new ProBlock();
|
2010-06-08 13:57:23 +02:00
|
|
|
QString buf = args.join(statics.field_sep);
|
2010-01-18 22:57:45 +01:00
|
|
|
if (!readInternal(pro, buf, (ushort*)buf.data())) {
|
2009-10-02 17:37:02 +02:00
|
|
|
delete pro;
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
2010-02-02 21:00:09 +01:00
|
|
|
bool ret = visitProBlock(pro);
|
2009-10-02 17:37:02 +02:00
|
|
|
pro->deref();
|
|
|
|
|
return returnBool(ret);
|
|
|
|
|
}
|
2009-05-19 19:00:06 +02:00
|
|
|
case T_FOR: {
|
|
|
|
|
if (m_cumulative) // This is a no-win situation, so just pretend it's no loop
|
|
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
if (m_skipLevel)
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
if (args.count() > 2 || args.count() < 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("for({var, list|var, forever|ever})"
|
2009-05-19 19:00:06 +02:00
|
|
|
" requires one or two arguments."));
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
|
|
|
|
ProLoop loop;
|
|
|
|
|
loop.infinite = false;
|
|
|
|
|
loop.index = 0;
|
|
|
|
|
QString it_list;
|
|
|
|
|
if (args.count() == 1) {
|
|
|
|
|
it_list = args[0];
|
2010-02-08 17:15:44 +01:00
|
|
|
if (args[0] != statics.strever) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("for({var, list|var, forever|ever})"
|
2009-05-19 19:00:06 +02:00
|
|
|
" requires one or two arguments."));
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
2010-02-08 17:15:44 +01:00
|
|
|
it_list = statics.strforever;
|
2009-05-19 19:00:06 +02:00
|
|
|
} else {
|
2010-02-11 16:33:16 +01:00
|
|
|
loop.variable = map(args.at(0));
|
2010-02-09 20:38:21 +01:00
|
|
|
loop.oldVarVal = valuesDirect(loop.variable);
|
2010-02-11 16:33:16 +01:00
|
|
|
it_list = map(args.at(1));
|
2009-05-19 19:00:06 +02:00
|
|
|
}
|
2010-02-09 20:38:21 +01:00
|
|
|
loop.list = valuesDirect(it_list);
|
2009-05-19 19:00:06 +02:00
|
|
|
if (loop.list.isEmpty()) {
|
2010-02-08 17:15:44 +01:00
|
|
|
if (it_list == statics.strforever) {
|
2009-05-19 19:00:06 +02:00
|
|
|
loop.infinite = true;
|
|
|
|
|
} else {
|
2010-02-08 17:15:44 +01:00
|
|
|
int dotdot = it_list.indexOf(statics.strDotDot);
|
2009-05-19 19:00:06 +02:00
|
|
|
if (dotdot != -1) {
|
|
|
|
|
bool ok;
|
|
|
|
|
int start = it_list.left(dotdot).toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
int end = it_list.mid(dotdot+2).toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
if (start < end) {
|
|
|
|
|
for (int i = start; i <= end; i++)
|
|
|
|
|
loop.list << QString::number(i);
|
|
|
|
|
} else {
|
|
|
|
|
for (int i = start; i >= end; i--)
|
|
|
|
|
loop.list << QString::number(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_loopStack.push(loop);
|
|
|
|
|
m_sts.condition = true;
|
|
|
|
|
return ProItem::ReturnLoop;
|
|
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_BREAK:
|
2009-05-19 19:00:06 +02:00
|
|
|
if (m_skipLevel)
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
if (!m_loopStack.isEmpty())
|
|
|
|
|
return ProItem::ReturnBreak;
|
|
|
|
|
// ### missing: breaking out of multiline blocks
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("unexpected break()."));
|
2009-05-19 19:00:06 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_NEXT:
|
2009-05-19 19:00:06 +02:00
|
|
|
if (m_skipLevel)
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
if (!m_loopStack.isEmpty())
|
|
|
|
|
return ProItem::ReturnNext;
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("unexpected next()."));
|
2009-05-19 19:00:06 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2009-05-18 15:42:45 +02:00
|
|
|
case T_IF: {
|
|
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("if(condition) requires one argument."));
|
2009-05-18 15:42:45 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
|
|
|
|
QString cond = args.first();
|
|
|
|
|
bool escaped = false; // This is more than qmake does
|
|
|
|
|
bool quoted = false;
|
|
|
|
|
bool ret = true;
|
|
|
|
|
bool orOp = false;
|
|
|
|
|
bool invert = false;
|
|
|
|
|
bool isFunc = false;
|
|
|
|
|
int parens = 0;
|
|
|
|
|
QString test;
|
|
|
|
|
test.reserve(20);
|
|
|
|
|
QString args;
|
|
|
|
|
args.reserve(50);
|
|
|
|
|
const QChar *d = cond.unicode();
|
|
|
|
|
const QChar *ed = d + cond.length();
|
|
|
|
|
while (d < ed) {
|
|
|
|
|
ushort c = (d++)->unicode();
|
|
|
|
|
if (!escaped) {
|
|
|
|
|
if (c == '\\') {
|
|
|
|
|
escaped = true;
|
|
|
|
|
args += c; // Assume no-one quotes the test name
|
|
|
|
|
continue;
|
|
|
|
|
} else if (c == '"') {
|
|
|
|
|
quoted = !quoted;
|
|
|
|
|
args += c; // Ditto
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
escaped = false;
|
|
|
|
|
}
|
|
|
|
|
if (quoted) {
|
|
|
|
|
args += c; // Ditto
|
|
|
|
|
} else {
|
|
|
|
|
bool isOp = false;
|
|
|
|
|
if (c == '(') {
|
|
|
|
|
isFunc = true;
|
|
|
|
|
if (parens)
|
|
|
|
|
args += c;
|
|
|
|
|
++parens;
|
|
|
|
|
} else if (c == ')') {
|
|
|
|
|
--parens;
|
|
|
|
|
if (parens)
|
|
|
|
|
args += c;
|
|
|
|
|
} else if (!parens) {
|
|
|
|
|
if (c == ':' || c == '|')
|
|
|
|
|
isOp = true;
|
|
|
|
|
else if (c == '!')
|
|
|
|
|
invert = true;
|
|
|
|
|
else
|
|
|
|
|
test += c;
|
|
|
|
|
} else {
|
|
|
|
|
args += c;
|
|
|
|
|
}
|
|
|
|
|
if (!parens && (isOp || d == ed)) {
|
|
|
|
|
// Yes, qmake doesn't shortcut evaluations here. We can't, either,
|
|
|
|
|
// as some test functions have side effects.
|
|
|
|
|
bool success;
|
|
|
|
|
if (isFunc) {
|
|
|
|
|
success = evaluateConditionalFunction(test, args);
|
|
|
|
|
} else {
|
|
|
|
|
success = isActiveConfig(test, true);
|
|
|
|
|
}
|
|
|
|
|
success ^= invert;
|
|
|
|
|
if (orOp)
|
|
|
|
|
ret |= success;
|
|
|
|
|
else
|
|
|
|
|
ret &= success;
|
|
|
|
|
orOp = (c == '|');
|
|
|
|
|
invert = false;
|
|
|
|
|
isFunc = false;
|
|
|
|
|
test.clear();
|
|
|
|
|
args.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return returnBool(ret);
|
|
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_CONFIG: {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() < 1 || args.count() > 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("CONFIG(config) requires one or two arguments."));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-10 13:20:16 +01:00
|
|
|
if (args.count() == 1)
|
|
|
|
|
return returnBool(isActiveConfig(args.first()));
|
2008-12-02 12:01:29 +01:00
|
|
|
const QStringList mutuals = args[1].split(QLatin1Char('|'));
|
2010-02-08 17:15:44 +01:00
|
|
|
const QStringList &configs = valuesDirect(statics.strCONFIG);
|
2009-03-19 15:04:43 +01:00
|
|
|
|
2009-02-04 20:41:41 +01:00
|
|
|
for (int i = configs.size() - 1; i >= 0; i--) {
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int mut = 0; mut < mutuals.count(); mut++) {
|
|
|
|
|
if (configs[i] == mutuals[mut].trimmed()) {
|
2009-05-18 17:46:30 +02:00
|
|
|
return returnBool(configs[i] == args[0]);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_CONTAINS: {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() < 2 || args.count() > 3) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("contains(var, val) requires two or three arguments."));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-01-19 18:36:03 +01:00
|
|
|
const QString &qry = args.at(1);
|
|
|
|
|
QRegExp regx;
|
|
|
|
|
if (qry != QRegExp::escape(qry))
|
|
|
|
|
regx.setPattern(qry);
|
2010-02-11 16:33:16 +01:00
|
|
|
const QStringList &l = values(map(args.first()));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() == 2) {
|
|
|
|
|
for (int i = 0; i < l.size(); ++i) {
|
|
|
|
|
const QString val = l[i];
|
2010-01-19 18:36:03 +01:00
|
|
|
if ((!regx.isEmpty() && regx.exactMatch(val)) || val == qry)
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const QStringList mutuals = args[2].split(QLatin1Char('|'));
|
|
|
|
|
for (int i = l.size() - 1; i >= 0; i--) {
|
|
|
|
|
const QString val = l[i];
|
|
|
|
|
for (int mut = 0; mut < mutuals.count(); mut++) {
|
|
|
|
|
if (val == mutuals[mut].trimmed()) {
|
2010-01-19 18:36:03 +01:00
|
|
|
return returnBool((!regx.isEmpty() && regx.exactMatch(val))
|
|
|
|
|
|| val == qry);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-11 15:53:35 +01:00
|
|
|
case T_COUNT: {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() != 2 && args.count() != 3) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("count(var, count, op=\"equals\") requires two or three arguments."));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-11 16:33:16 +01:00
|
|
|
int cnt = values(map(args.first())).count();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() == 3) {
|
|
|
|
|
QString comp = args[2];
|
|
|
|
|
if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
|
2010-02-11 15:53:35 +01:00
|
|
|
return returnBool(cnt > args[1].toInt());
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (comp == QLatin1String(">=")) {
|
2010-02-11 15:53:35 +01:00
|
|
|
return returnBool(cnt >= args[1].toInt());
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) {
|
2010-02-11 15:53:35 +01:00
|
|
|
return returnBool(cnt < args[1].toInt());
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (comp == QLatin1String("<=")) {
|
2010-02-11 15:53:35 +01:00
|
|
|
return returnBool(cnt <= args[1].toInt());
|
2009-05-12 17:15:54 +02:00
|
|
|
} else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual")
|
|
|
|
|
|| comp == QLatin1String("=") || comp == QLatin1String("==")) {
|
2010-02-11 15:53:35 +01:00
|
|
|
return returnBool(cnt == args[1].toInt());
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("unexpected modifier to count(%2)").arg(comp));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-02-11 15:53:35 +01:00
|
|
|
return returnBool(cnt == args[1].toInt());
|
|
|
|
|
}
|
2009-05-14 17:14:37 +02:00
|
|
|
case T_GREATERTHAN:
|
|
|
|
|
case T_LESSTHAN: {
|
|
|
|
|
if (args.count() != 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("%1(variable, value) requires two arguments.").arg(function));
|
2009-05-14 17:14:37 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
2010-02-11 16:33:16 +01:00
|
|
|
QString rhs(args[1]), lhs(values(map(args.at(0))).join(statics.field_sep));
|
2009-05-14 17:14:37 +02:00
|
|
|
bool ok;
|
|
|
|
|
int rhs_int = rhs.toInt(&ok);
|
|
|
|
|
if (ok) { // do integer compare
|
|
|
|
|
int lhs_int = lhs.toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
if (func_t == T_GREATERTHAN)
|
|
|
|
|
return returnBool(lhs_int > rhs_int);
|
|
|
|
|
return returnBool(lhs_int < rhs_int);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (func_t == T_GREATERTHAN)
|
|
|
|
|
return returnBool(lhs > rhs);
|
|
|
|
|
return returnBool(lhs < rhs);
|
|
|
|
|
}
|
|
|
|
|
case T_EQUALS:
|
|
|
|
|
if (args.count() != 2) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("%1(variable, value) requires two arguments.").arg(function));
|
2009-05-14 17:14:37 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
2010-02-11 16:33:16 +01:00
|
|
|
return returnBool(values(map(args.at(0))).join(statics.field_sep) == args.at(1));
|
2009-05-14 17:14:37 +02:00
|
|
|
case T_CLEAR: {
|
|
|
|
|
if (m_skipLevel && !m_cumulative)
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("%1(variable) requires one argument.").arg(function));
|
2009-05-14 17:14:37 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
2010-02-09 20:38:21 +01:00
|
|
|
QHash<QString, QStringList> *hsh;
|
|
|
|
|
QHash<QString, QStringList>::Iterator it;
|
2010-02-11 16:33:16 +01:00
|
|
|
const QString &var = map(args.at(0));
|
|
|
|
|
if (!(hsh = findValues(var, &it)))
|
2009-05-14 17:14:37 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2010-02-09 20:38:21 +01:00
|
|
|
if (hsh == &m_valuemapStack.top())
|
|
|
|
|
it->clear();
|
|
|
|
|
else
|
2010-02-11 16:33:16 +01:00
|
|
|
m_valuemapStack.top()[var].clear();
|
2009-05-14 17:14:37 +02:00
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
}
|
|
|
|
|
case T_UNSET: {
|
|
|
|
|
if (m_skipLevel && !m_cumulative)
|
|
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("%1(variable) requires one argument.").arg(function));
|
2009-05-14 17:14:37 +02:00
|
|
|
return ProItem::ReturnFalse;
|
|
|
|
|
}
|
2010-02-09 20:38:21 +01:00
|
|
|
QHash<QString, QStringList> *hsh;
|
|
|
|
|
QHash<QString, QStringList>::Iterator it;
|
2010-02-11 16:33:16 +01:00
|
|
|
const QString &var = map(args.at(0));
|
|
|
|
|
if (!(hsh = findValues(var, &it)))
|
2009-05-14 17:14:37 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2010-02-09 20:38:21 +01:00
|
|
|
if (m_valuemapStack.size() == 1)
|
|
|
|
|
hsh->erase(it);
|
|
|
|
|
else if (hsh == &m_valuemapStack.top())
|
|
|
|
|
*it = statics.fakeValue;
|
|
|
|
|
else
|
2010-02-11 16:33:16 +01:00
|
|
|
m_valuemapStack.top()[var] = statics.fakeValue;
|
2009-05-14 17:14:37 +02:00
|
|
|
return ProItem::ReturnTrue;
|
|
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_INCLUDE: {
|
2008-12-17 18:52:14 +01:00
|
|
|
if (m_skipLevel && !m_cumulative)
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
QString parseInto;
|
2009-08-14 15:41:26 +10:00
|
|
|
// the third optional argument to include() controls warnings
|
|
|
|
|
// and is not used here
|
|
|
|
|
if ((args.count() == 2) || (args.count() == 3) ) {
|
2008-12-02 12:01:29 +01:00
|
|
|
parseInto = args[1];
|
|
|
|
|
} else if (args.count() != 1) {
|
2010-02-11 14:13:59 +01:00
|
|
|
logMessage(format("include(file, into, silent) requires one, two or three arguments."));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-11 14:13:59 +01:00
|
|
|
QString fn = resolvePath(expandEnvVars(args.first()));
|
|
|
|
|
bool ok;
|
|
|
|
|
if (parseInto.isEmpty()) {
|
|
|
|
|
State sts = m_sts;
|
|
|
|
|
ok = evaluateFile(fn);
|
|
|
|
|
m_sts = sts;
|
|
|
|
|
} else {
|
|
|
|
|
QHash<QString, QStringList> symbols;
|
2010-02-15 17:12:32 +01:00
|
|
|
if ((ok = evaluateFileInto(fn, &symbols, 0))) {
|
|
|
|
|
QHash<QString, QStringList> newMap;
|
|
|
|
|
for (QHash<QString, QStringList>::ConstIterator
|
|
|
|
|
it = m_valuemapStack.top().constBegin(),
|
|
|
|
|
end = m_valuemapStack.top().constEnd();
|
|
|
|
|
it != end; ++it)
|
|
|
|
|
if (!(it.key().startsWith(parseInto) &&
|
|
|
|
|
(it.key().length() == parseInto.length()
|
|
|
|
|
|| it.key().at(parseInto.length()) == QLatin1Char('.'))))
|
|
|
|
|
newMap[it.key()] = it.value();
|
2010-02-11 14:13:59 +01:00
|
|
|
for (QHash<QString, QStringList>::ConstIterator it = symbols.constBegin();
|
|
|
|
|
it != symbols.constEnd(); ++it)
|
|
|
|
|
if (!it.key().startsWith(QLatin1Char('.')))
|
2010-02-15 17:12:32 +01:00
|
|
|
newMap.insert(parseInto + QLatin1Char('.') + it.key(), it.value());
|
|
|
|
|
m_valuemapStack.top() = newMap;
|
|
|
|
|
}
|
2010-02-11 14:13:59 +01:00
|
|
|
}
|
2009-05-18 17:46:30 +02:00
|
|
|
return returnBool(ok);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_LOAD: {
|
2008-12-17 18:52:14 +01:00
|
|
|
if (m_skipLevel && !m_cumulative)
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
bool ignore_error = false;
|
|
|
|
|
if (args.count() == 2) {
|
|
|
|
|
QString sarg = args[1];
|
2010-02-08 17:15:44 +01:00
|
|
|
ignore_error = (!sarg.compare(statics.strtrue, Qt::CaseInsensitive) || sarg.toInt());
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("load(feature) requires one or two arguments."));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-05-12 17:15:54 +02:00
|
|
|
// XXX ignore_error unused
|
2010-02-11 12:42:40 +01:00
|
|
|
return returnBool(evaluateFeatureFile(expandEnvVars(args.first())));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_DEBUG:
|
|
|
|
|
// Yup - do nothing. Nothing is going to enable debug output anyway.
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_MESSAGE: {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("%1(message) requires one argument.").arg(function));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-07-23 17:04:50 +02:00
|
|
|
QString msg = expandEnvVars(args.first());
|
2009-08-12 13:00:21 +02:00
|
|
|
fileMessage(QString::fromLatin1("Project %1: %2").arg(function.toUpper(), msg));
|
2009-05-20 14:35:00 +02:00
|
|
|
// ### Consider real termination in non-cumulative mode
|
|
|
|
|
return returnBool(function != QLatin1String("error"));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
#if 0 // Way too dangerous to enable.
|
|
|
|
|
case T_SYSTEM: {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("system(exec) requires one argument."));
|
2009-05-18 17:46:30 +02:00
|
|
|
ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-03 18:16:46 +01:00
|
|
|
return returnBool(system((QLatin1String("cd ")
|
|
|
|
|
+ IoUtils::shellQuote(currentDirectory())
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
+ QLatin1String(" && ") + args.first()).toLocal8Bit().constData()) == 0);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
#endif
|
|
|
|
|
case T_ISEMPTY: {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("isEmpty(var) requires one argument."));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-11 16:33:16 +01:00
|
|
|
QStringList sl = values(map(args.first()));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (sl.count() == 0) {
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (sl.count() > 0) {
|
|
|
|
|
QString var = sl.first();
|
2009-05-12 17:15:54 +02:00
|
|
|
if (var.isEmpty())
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_EXISTS: {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() != 1) {
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("exists(file) requires one argument."));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-11 12:42:40 +01:00
|
|
|
QString file = resolvePath(expandEnvVars(args.first()));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(file)) {
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-11 12:41:16 +01:00
|
|
|
int slsh = file.lastIndexOf(QLatin1Char('/'));
|
|
|
|
|
QString fn = file.mid(slsh+1);
|
|
|
|
|
if (fn.contains(QLatin1Char('*')) || fn.contains(QLatin1Char('?'))) {
|
|
|
|
|
QString dirstr = file.left(slsh+1);
|
|
|
|
|
if (!QDir(dirstr).entryList(QStringList(fn)).isEmpty())
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnTrue;
|
2010-02-11 12:41:16 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case 0:
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("'%1' is not a recognized test function").arg(function));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-17 18:47:12 +01:00
|
|
|
default:
|
2009-08-12 13:00:21 +02:00
|
|
|
logMessage(format("Function '%1' is not implemented").arg(function));
|
2009-05-18 17:46:30 +02:00
|
|
|
return ProItem::ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-09 20:38:21 +01:00
|
|
|
QHash<QString, QStringList> *ProFileEvaluator::Private::findValues(
|
|
|
|
|
const QString &variableName, QHash<QString, QStringList>::Iterator *rit)
|
|
|
|
|
{
|
|
|
|
|
for (int i = m_valuemapStack.size(); --i >= 0; ) {
|
|
|
|
|
QHash<QString, QStringList>::Iterator it = m_valuemapStack[i].find(variableName);
|
|
|
|
|
if (it != m_valuemapStack[i].end()) {
|
|
|
|
|
if (it->constBegin() == statics.fakeValue.constBegin())
|
|
|
|
|
return 0;
|
|
|
|
|
*rit = it;
|
|
|
|
|
return &m_valuemapStack[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList &ProFileEvaluator::Private::valuesRef(const QString &variableName)
|
|
|
|
|
{
|
|
|
|
|
QHash<QString, QStringList>::Iterator it = m_valuemapStack.top().find(variableName);
|
|
|
|
|
if (it != m_valuemapStack.top().end())
|
|
|
|
|
return *it;
|
|
|
|
|
for (int i = m_valuemapStack.size() - 1; --i >= 0; ) {
|
|
|
|
|
QHash<QString, QStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
|
|
|
|
|
if (it != m_valuemapStack.at(i).constEnd()) {
|
|
|
|
|
QStringList &ret = m_valuemapStack.top()[variableName];
|
|
|
|
|
ret = *it;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return m_valuemapStack.top()[variableName];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList ProFileEvaluator::Private::valuesDirect(const QString &variableName) const
|
|
|
|
|
{
|
|
|
|
|
for (int i = m_valuemapStack.size(); --i >= 0; ) {
|
|
|
|
|
QHash<QString, QStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
|
|
|
|
|
if (it != m_valuemapStack.at(i).constEnd()) {
|
|
|
|
|
if (it->constBegin() == statics.fakeValue.constBegin())
|
|
|
|
|
break;
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return QStringList();
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-09 14:58:59 +01:00
|
|
|
QStringList ProFileEvaluator::Private::values(const QString &variableName) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-02-08 16:47:25 +01:00
|
|
|
QHash<QString, int>::ConstIterator vli = statics.varList.find(variableName);
|
|
|
|
|
if (vli != statics.varList.constEnd()) {
|
2010-02-02 19:01:23 +01:00
|
|
|
int vlidx = *vli;
|
|
|
|
|
QString ret;
|
|
|
|
|
switch ((VarName)vlidx) {
|
|
|
|
|
case V_LITERAL_WHITESPACE: ret = QLatin1String("\t"); break;
|
|
|
|
|
case V_LITERAL_DOLLAR: ret = QLatin1String("$"); break;
|
|
|
|
|
case V_LITERAL_HASH: ret = QLatin1String("#"); break;
|
|
|
|
|
case V_OUT_PWD: //the outgoing dir
|
|
|
|
|
ret = m_outputDir;
|
|
|
|
|
break;
|
|
|
|
|
case V_PWD: //current working dir (of _FILE_)
|
|
|
|
|
case V_IN_PWD:
|
|
|
|
|
ret = currentDirectory();
|
|
|
|
|
break;
|
|
|
|
|
case V_DIR_SEPARATOR:
|
|
|
|
|
ret = m_option->dir_sep;
|
|
|
|
|
break;
|
|
|
|
|
case V_DIRLIST_SEPARATOR:
|
|
|
|
|
ret = m_option->dirlist_sep;
|
|
|
|
|
break;
|
|
|
|
|
case V__LINE_: //parser line number
|
|
|
|
|
ret = QString::number(m_lineNo);
|
|
|
|
|
break;
|
|
|
|
|
case V__FILE_: //parser file; qmake is a bit weird here
|
2010-02-09 14:58:59 +01:00
|
|
|
ret = m_profileStack.size() == 1 ? currentFileName() : currentProFile()->displayFileName();
|
2010-02-02 19:01:23 +01:00
|
|
|
break;
|
|
|
|
|
case V__DATE_: //current date/time
|
|
|
|
|
ret = QDateTime::currentDateTime().toString();
|
|
|
|
|
break;
|
|
|
|
|
case V__PRO_FILE_:
|
|
|
|
|
ret = m_profileStack.first()->fileName();
|
|
|
|
|
break;
|
|
|
|
|
case V__PRO_FILE_PWD_:
|
|
|
|
|
ret = m_profileStack.first()->directoryName();
|
|
|
|
|
break;
|
|
|
|
|
case V__QMAKE_CACHE_:
|
|
|
|
|
ret = m_option->cachefile;
|
|
|
|
|
break;
|
2008-12-12 16:30:31 +01:00
|
|
|
#if defined(Q_OS_WIN32)
|
2010-02-02 19:01:23 +01:00
|
|
|
case V_QMAKE_HOST_os: ret = QLatin1String("Windows"); break;
|
2010-02-05 16:20:33 +01:00
|
|
|
case V_QMAKE_HOST_name: {
|
2008-12-12 16:30:31 +01:00
|
|
|
DWORD name_length = 1024;
|
|
|
|
|
TCHAR name[1024];
|
|
|
|
|
if (GetComputerName(name, &name_length))
|
|
|
|
|
ret = QString::fromUtf16((ushort*)name, name_length);
|
2010-02-02 19:01:23 +01:00
|
|
|
break;
|
2010-02-05 16:20:33 +01:00
|
|
|
}
|
2010-02-02 19:01:23 +01:00
|
|
|
case V_QMAKE_HOST_version:
|
|
|
|
|
ret = QString::number(QSysInfo::WindowsVersion);
|
|
|
|
|
break;
|
|
|
|
|
case V_QMAKE_HOST_version_string:
|
|
|
|
|
switch (QSysInfo::WindowsVersion) {
|
|
|
|
|
case QSysInfo::WV_Me: ret = QLatin1String("WinMe"); break;
|
|
|
|
|
case QSysInfo::WV_95: ret = QLatin1String("Win95"); break;
|
|
|
|
|
case QSysInfo::WV_98: ret = QLatin1String("Win98"); break;
|
|
|
|
|
case QSysInfo::WV_NT: ret = QLatin1String("WinNT"); break;
|
|
|
|
|
case QSysInfo::WV_2000: ret = QLatin1String("Win2000"); break;
|
|
|
|
|
case QSysInfo::WV_2003: ret = QLatin1String("Win2003"); break;
|
|
|
|
|
case QSysInfo::WV_XP: ret = QLatin1String("WinXP"); break;
|
|
|
|
|
case QSysInfo::WV_VISTA: ret = QLatin1String("WinVista"); break;
|
|
|
|
|
default: ret = QLatin1String("Unknown"); break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case V_QMAKE_HOST_arch:
|
2008-12-12 16:30:31 +01:00
|
|
|
SYSTEM_INFO info;
|
|
|
|
|
GetSystemInfo(&info);
|
|
|
|
|
switch(info.wProcessorArchitecture) {
|
|
|
|
|
#ifdef PROCESSOR_ARCHITECTURE_AMD64
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
|
|
|
ret = QLatin1String("x86_64");
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
|
|
|
ret = QLatin1String("x86");
|
|
|
|
|
break;
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
|
|
|
#ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
|
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
|
|
|
|
|
#endif
|
|
|
|
|
ret = QLatin1String("IA64");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ret = QLatin1String("Unknown");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-02-02 19:01:23 +01:00
|
|
|
break;
|
2008-12-12 16:30:31 +01:00
|
|
|
#elif defined(Q_OS_UNIX)
|
2010-02-02 19:01:23 +01:00
|
|
|
case V_QMAKE_HOST_os:
|
|
|
|
|
case V_QMAKE_HOST_name:
|
|
|
|
|
case V_QMAKE_HOST_version:
|
|
|
|
|
case V_QMAKE_HOST_version_string:
|
|
|
|
|
case V_QMAKE_HOST_arch:
|
|
|
|
|
{
|
|
|
|
|
struct utsname name;
|
|
|
|
|
const char *what;
|
|
|
|
|
if (!uname(&name)) {
|
|
|
|
|
switch (vlidx) {
|
|
|
|
|
case V_QMAKE_HOST_os: what = name.sysname; break;
|
|
|
|
|
case V_QMAKE_HOST_name: what = name.nodename; break;
|
|
|
|
|
case V_QMAKE_HOST_version: what = name.release; break;
|
|
|
|
|
case V_QMAKE_HOST_version_string: what = name.version; break;
|
|
|
|
|
case V_QMAKE_HOST_arch: what = name.machine; break;
|
|
|
|
|
}
|
try to sort out the filename encoding mess
use local8bit instead of latin1 resp. 8bit-passthrough, after all.
the situation was as follows:
- if the pro files and file names were all ascii, everything just worked
- if either contained non-ascii:
- on unix, the evaluator would work as long as the file content
encoding matched the file name encoding, and the ui would work as
long as the file name encoding was latin1 (i.e., on no modern
system)
- on windows, both would work only if the ansi code page was
latin1/cp1252 (i.e., on western systems)
i.e., even in the low-level evaluator, only native latin1 systems with
actual latin1 files worked consistently. given this situation, it makes
little sense to make an encoding adapter between the evaluator and the
ui as originally planned. instead, take the easy way out and use
local8bit - this continues to work for native latin1 systems+files in
the backend, and makes the ui work for everything the backend groks and
some more.
Reviewed-by: dt
Task-number: QTCREATORBUG-930
2010-06-08 17:49:09 +02:00
|
|
|
ret = QString::fromLocal8Bit(what);
|
2010-02-02 19:01:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
#endif
|
2010-02-02 19:01:23 +01:00
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
return QStringList(ret);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-09 14:58:59 +01:00
|
|
|
QStringList result = valuesDirect(variableName);
|
2008-12-12 16:30:31 +01:00
|
|
|
if (result.isEmpty()) {
|
2010-02-08 17:15:44 +01:00
|
|
|
if (variableName == statics.strTEMPLATE) {
|
2008-12-12 16:30:31 +01:00
|
|
|
result.append(QLatin1String("app"));
|
2010-02-08 17:15:44 +01:00
|
|
|
} else if (variableName == statics.strQMAKE_DIR_SEP) {
|
2009-07-23 18:36:59 +02:00
|
|
|
result.append(m_option->dirlist_sep);
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-07 22:58:47 +01:00
|
|
|
ProFile *ProFileEvaluator::Private::parsedProFile(const QString &fileName, bool cache,
|
|
|
|
|
const QString &contents)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-12-07 22:58:47 +01:00
|
|
|
ProFile *pro;
|
2010-02-26 12:53:30 +01:00
|
|
|
if (cache && m_option->cache) {
|
|
|
|
|
ProFileCache::Entry *ent;
|
|
|
|
|
#ifdef PROPARSER_THREAD_SAFE
|
|
|
|
|
QMutexLocker locker(&m_option->cache->mutex);
|
|
|
|
|
#endif
|
|
|
|
|
QHash<QString, ProFileCache::Entry>::Iterator it =
|
|
|
|
|
m_option->cache->parsed_files.find(fileName);
|
|
|
|
|
if (it != m_option->cache->parsed_files.end()) {
|
|
|
|
|
ent = &*it;
|
|
|
|
|
#ifdef PROPARSER_THREAD_SAFE
|
2010-03-17 16:19:55 +01:00
|
|
|
if (ent->locker && !ent->locker->done) {
|
2010-02-26 12:53:30 +01:00
|
|
|
++ent->locker->waiters;
|
|
|
|
|
QThreadPool::globalInstance()->releaseThread();
|
|
|
|
|
ent->locker->cond.wait(locker.mutex());
|
|
|
|
|
QThreadPool::globalInstance()->reserveThread();
|
|
|
|
|
if (!--ent->locker->waiters) {
|
|
|
|
|
delete ent->locker;
|
|
|
|
|
ent->locker = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if ((pro = ent->pro))
|
|
|
|
|
pro->ref();
|
|
|
|
|
} else {
|
|
|
|
|
ent = &m_option->cache->parsed_files[fileName];
|
|
|
|
|
#ifdef PROPARSER_THREAD_SAFE
|
|
|
|
|
ent->locker = new ProFileCache::Entry::Locker;
|
|
|
|
|
locker.unlock();
|
|
|
|
|
#endif
|
|
|
|
|
pro = new ProFile(fileName);
|
|
|
|
|
if (!(contents.isNull() ? read(pro) : read(pro, contents))) {
|
|
|
|
|
delete pro;
|
|
|
|
|
pro = 0;
|
|
|
|
|
} else {
|
|
|
|
|
pro->ref();
|
|
|
|
|
}
|
|
|
|
|
ent->pro = pro;
|
|
|
|
|
#ifdef PROPARSER_THREAD_SAFE
|
|
|
|
|
locker.relock();
|
|
|
|
|
if (ent->locker->waiters) {
|
2010-03-17 16:19:55 +01:00
|
|
|
ent->locker->done = true;
|
2010-02-26 12:53:30 +01:00
|
|
|
ent->locker->cond.wakeAll();
|
|
|
|
|
} else {
|
|
|
|
|
delete ent->locker;
|
|
|
|
|
ent->locker = 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2009-12-07 22:58:47 +01:00
|
|
|
pro = new ProFile(fileName);
|
|
|
|
|
if (!(contents.isNull() ? read(pro) : read(pro, contents))) {
|
|
|
|
|
delete pro;
|
2010-02-26 12:50:57 +01:00
|
|
|
pro = 0;
|
2009-12-07 22:58:47 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return pro;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-07 21:25:11 +02:00
|
|
|
bool ProFileEvaluator::Private::evaluateFileDirect(
|
|
|
|
|
const QString &fileName, ProFileEvaluator::EvalFileType type)
|
|
|
|
|
{
|
|
|
|
|
if (ProFile *pro = parsedProFile(fileName, true)) {
|
|
|
|
|
q->aboutToEval(currentProFile(), pro, type);
|
|
|
|
|
bool ok = (visitProFile(pro) == ProItem::ReturnTrue);
|
|
|
|
|
q->doneWithEval(currentProFile());
|
|
|
|
|
pro->deref();
|
|
|
|
|
return ok;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-12 17:15:54 +02:00
|
|
|
bool ProFileEvaluator::Private::evaluateFile(const QString &fileName)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-01-22 12:26:14 +01:00
|
|
|
if (fileName.isEmpty())
|
2009-08-04 20:39:28 +02:00
|
|
|
return false;
|
|
|
|
|
foreach (const ProFile *pf, m_profileStack)
|
2010-01-22 12:26:14 +01:00
|
|
|
if (pf->fileName() == fileName) {
|
|
|
|
|
errorMessage(format("circular inclusion of %1").arg(fileName));
|
2009-08-04 20:39:28 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2010-06-07 21:25:11 +02:00
|
|
|
return evaluateFileDirect(fileName, ProFileEvaluator::EvalIncludeFile);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-08-04 16:16:27 +02:00
|
|
|
bool ProFileEvaluator::Private::evaluateFeatureFile(
|
2009-08-10 17:27:07 +02:00
|
|
|
const QString &fileName, QHash<QString, QStringList> *values, FunctionDefs *funcs)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-08-04 16:16:27 +02:00
|
|
|
QString fn = fileName;
|
2009-07-20 16:58:29 +02:00
|
|
|
if (!fn.endsWith(QLatin1String(".prf")))
|
|
|
|
|
fn += QLatin1String(".prf");
|
2009-08-04 16:16:27 +02:00
|
|
|
|
2010-02-03 18:16:46 +01:00
|
|
|
if (!fileName.contains((ushort)'/') || !IoUtils::exists(resolvePath(fn))) {
|
2009-08-04 16:16:27 +02:00
|
|
|
if (m_option->feature_roots.isEmpty())
|
|
|
|
|
m_option->feature_roots = qmakeFeaturePaths();
|
|
|
|
|
int start_root = 0;
|
|
|
|
|
QString currFn = currentFileName();
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::fileName(currFn) == IoUtils::fileName(fn)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
for (int root = 0; root < m_option->feature_roots.size(); ++root)
|
2010-02-08 11:07:18 +01:00
|
|
|
if (currFn == m_option->feature_roots.at(root) + fn) {
|
2009-08-04 16:16:27 +02:00
|
|
|
start_root = root + 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int root = start_root; root < m_option->feature_roots.size(); ++root) {
|
|
|
|
|
QString fname = m_option->feature_roots.at(root) + fn;
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(fname)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
fn = fname;
|
|
|
|
|
goto cool;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-08-04 16:16:27 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
cool:
|
|
|
|
|
// It's beyond me why qmake has this inside this if ...
|
2010-02-09 20:38:21 +01:00
|
|
|
QStringList &already = valuesRef(QLatin1String("QMAKE_INTERNAL_INCLUDED_FEATURES"));
|
2009-08-04 16:16:27 +02:00
|
|
|
if (already.contains(fn))
|
|
|
|
|
return true;
|
|
|
|
|
already.append(fn);
|
|
|
|
|
} else {
|
2010-01-22 12:26:14 +01:00
|
|
|
fn = resolvePath(fn);
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (values) {
|
2009-08-10 17:27:07 +02:00
|
|
|
return evaluateFileInto(fn, values, funcs);
|
2009-08-04 16:16:27 +02:00
|
|
|
} else {
|
|
|
|
|
bool cumulative = m_cumulative;
|
|
|
|
|
m_cumulative = false;
|
2009-08-04 20:48:22 +02:00
|
|
|
|
|
|
|
|
// The path is fully normalized already.
|
2010-06-07 21:25:11 +02:00
|
|
|
bool ok = evaluateFileDirect(fn, ProFileEvaluator::EvalFeatureFile);
|
2009-08-04 20:48:22 +02:00
|
|
|
|
2009-08-04 16:16:27 +02:00
|
|
|
m_cumulative = cumulative;
|
|
|
|
|
return ok;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProFileEvaluator::Private::evaluateFileInto(
|
2009-08-10 17:27:07 +02:00
|
|
|
const QString &fileName, QHash<QString, QStringList> *values, FunctionDefs *funcs)
|
2009-08-04 16:16:27 +02:00
|
|
|
{
|
|
|
|
|
ProFileEvaluator visitor(m_option);
|
|
|
|
|
visitor.d->m_cumulative = false;
|
|
|
|
|
visitor.d->m_parsePreAndPostFiles = false;
|
|
|
|
|
visitor.d->m_verbose = m_verbose;
|
2010-02-09 20:38:21 +01:00
|
|
|
visitor.d->m_valuemapStack.top() = *values;
|
2009-08-10 17:27:07 +02:00
|
|
|
if (funcs)
|
|
|
|
|
visitor.d->m_functionDefs = *funcs;
|
2009-08-04 16:16:27 +02:00
|
|
|
if (!visitor.d->evaluateFile(fileName))
|
|
|
|
|
return false;
|
2010-02-09 20:38:21 +01:00
|
|
|
*values = visitor.d->m_valuemapStack.top();
|
2009-08-10 17:27:07 +02:00
|
|
|
if (funcs) {
|
|
|
|
|
*funcs = visitor.d->m_functionDefs;
|
|
|
|
|
// So they are not unref'd
|
|
|
|
|
visitor.d->m_functionDefs.testFunctions.clear();
|
|
|
|
|
visitor.d->m_functionDefs.replaceFunctions.clear();
|
|
|
|
|
}
|
2009-08-04 16:16:27 +02:00
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ProFileEvaluator::Private::format(const char *fmt) const
|
|
|
|
|
{
|
|
|
|
|
ProFile *pro = currentProFile();
|
|
|
|
|
QString fileName = pro ? pro->fileName() : QLatin1String("Not a file");
|
|
|
|
|
int lineNumber = pro ? m_lineNo : 0;
|
|
|
|
|
return QString::fromLatin1("%1(%2):").arg(fileName).arg(lineNumber) + QString::fromAscii(fmt);
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-12 13:00:21 +02:00
|
|
|
void ProFileEvaluator::Private::logMessage(const QString &message) const
|
|
|
|
|
{
|
|
|
|
|
if (m_verbose && !m_skipLevel)
|
|
|
|
|
q->logMessage(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::fileMessage(const QString &message) const
|
|
|
|
|
{
|
|
|
|
|
if (!m_skipLevel)
|
|
|
|
|
q->fileMessage(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::errorMessage(const QString &message) const
|
|
|
|
|
{
|
|
|
|
|
if (!m_skipLevel)
|
|
|
|
|
q->errorMessage(message);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// ProFileEvaluator
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-02-08 16:47:25 +01:00
|
|
|
void ProFileEvaluator::initialize()
|
|
|
|
|
{
|
|
|
|
|
Private::initStatics();
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-07 20:32:36 +01:00
|
|
|
ProFileEvaluator::ProFileEvaluator(ProFileOption *option)
|
2009-07-23 18:36:59 +02:00
|
|
|
: d(new Private(this, option))
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProFileEvaluator::~ProFileEvaluator()
|
|
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProFileEvaluator::contains(const QString &variableName) const
|
|
|
|
|
{
|
2010-02-09 20:38:21 +01:00
|
|
|
return d->m_valuemapStack.top().contains(variableName);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList ProFileEvaluator::values(const QString &variableName) const
|
|
|
|
|
{
|
2009-07-30 17:03:12 +02:00
|
|
|
return expandEnvVars(d->values(variableName));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const
|
|
|
|
|
{
|
2010-02-09 14:58:59 +01:00
|
|
|
// It makes no sense to put any kind of magic into expanding these
|
|
|
|
|
return expandEnvVars(d->m_filevaluemap.value(pro).value(variableName));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-07-10 13:37:02 +02:00
|
|
|
QStringList ProFileEvaluator::absolutePathValues(
|
|
|
|
|
const QString &variable, const QString &baseDirectory) const
|
|
|
|
|
{
|
|
|
|
|
QStringList result;
|
|
|
|
|
foreach (const QString &el, values(variable)) {
|
2010-01-22 12:26:14 +01:00
|
|
|
QString absEl = IoUtils::resolvePath(baseDirectory, el);
|
|
|
|
|
if (IoUtils::fileType(absEl) == IoUtils::FileIsDir)
|
|
|
|
|
result << QDir::cleanPath(absEl);
|
2009-07-10 13:37:02 +02:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList ProFileEvaluator::absoluteFileValues(
|
|
|
|
|
const QString &variable, const QString &baseDirectory, const QStringList &searchDirs,
|
|
|
|
|
const ProFile *pro) const
|
|
|
|
|
{
|
|
|
|
|
QStringList result;
|
|
|
|
|
foreach (const QString &el, pro ? values(variable, pro) : values(variable)) {
|
2010-01-22 12:26:14 +01:00
|
|
|
QString absEl;
|
|
|
|
|
if (IoUtils::isAbsolutePath(el)) {
|
|
|
|
|
if (IoUtils::exists(el)) {
|
2009-07-10 13:37:02 +02:00
|
|
|
result << QDir::cleanPath(el);
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
2010-01-22 12:26:14 +01:00
|
|
|
absEl = el;
|
2009-07-10 13:37:02 +02:00
|
|
|
} else {
|
|
|
|
|
foreach (const QString &dir, searchDirs) {
|
2010-01-22 12:26:14 +01:00
|
|
|
QString fn = dir + QLatin1Char('/') + el;
|
|
|
|
|
if (IoUtils::exists(fn)) {
|
|
|
|
|
result << QDir::cleanPath(fn);
|
2009-07-10 13:37:02 +02:00
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (baseDirectory.isEmpty())
|
|
|
|
|
goto next;
|
2010-01-22 12:26:14 +01:00
|
|
|
absEl = baseDirectory + QLatin1Char('/') + el;
|
2009-07-10 13:37:02 +02:00
|
|
|
}
|
|
|
|
|
{
|
2010-01-22 12:26:14 +01:00
|
|
|
absEl = QDir::cleanPath(absEl);
|
|
|
|
|
int nameOff = absEl.lastIndexOf(QLatin1Char('/'));
|
|
|
|
|
QString absDir = QString::fromRawData(absEl.constData(), nameOff);
|
|
|
|
|
if (IoUtils::exists(absDir)) {
|
|
|
|
|
QString wildcard = QString::fromRawData(absEl.constData() + nameOff + 1,
|
|
|
|
|
absEl.length() - nameOff - 1);
|
2009-07-10 13:37:02 +02:00
|
|
|
if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) {
|
2010-01-22 12:26:14 +01:00
|
|
|
QDir theDir(absDir);
|
2009-07-10 13:37:02 +02:00
|
|
|
foreach (const QString &fn, theDir.entryList(QStringList(wildcard)))
|
2010-02-08 17:15:44 +01:00
|
|
|
if (fn != statics.strDot && fn != statics.strDotDot)
|
2010-01-22 12:26:14 +01:00
|
|
|
result << absDir + QLatin1Char('/') + fn;
|
2009-07-10 13:37:02 +02:00
|
|
|
} // else if (acceptMissing)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
next: ;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
ProFileEvaluator::TemplateType ProFileEvaluator::templateType()
|
|
|
|
|
{
|
2010-02-08 17:15:44 +01:00
|
|
|
QStringList templ = values(statics.strTEMPLATE);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (templ.count() >= 1) {
|
2009-05-25 15:58:58 +02:00
|
|
|
const QString &t = templ.last();
|
|
|
|
|
if (!t.compare(QLatin1String("app"), Qt::CaseInsensitive))
|
2008-12-02 12:01:29 +01:00
|
|
|
return TT_Application;
|
2009-05-25 15:58:58 +02:00
|
|
|
if (!t.compare(QLatin1String("lib"), Qt::CaseInsensitive))
|
2008-12-02 12:01:29 +01:00
|
|
|
return TT_Library;
|
2009-05-25 15:58:58 +02:00
|
|
|
if (!t.compare(QLatin1String("script"), Qt::CaseInsensitive))
|
2008-12-02 12:01:29 +01:00
|
|
|
return TT_Script;
|
2009-05-25 15:58:58 +02:00
|
|
|
if (!t.compare(QLatin1String("subdirs"), Qt::CaseInsensitive))
|
2008-12-02 12:01:29 +01:00
|
|
|
return TT_Subdirs;
|
|
|
|
|
}
|
|
|
|
|
return TT_Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-07 22:58:47 +01:00
|
|
|
ProFile *ProFileEvaluator::parsedProFile(const QString &fileName, const QString &contents)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-12-07 22:58:47 +01:00
|
|
|
return d->parsedProFile(fileName, false, contents);
|
2009-07-07 13:13:12 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
bool ProFileEvaluator::accept(ProFile *pro)
|
|
|
|
|
{
|
2010-02-02 21:00:09 +01:00
|
|
|
return d->visitProFile(pro);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ProFileEvaluator::propertyValue(const QString &name) const
|
|
|
|
|
{
|
|
|
|
|
return d->propertyValue(name);
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-07 21:25:11 +02:00
|
|
|
void ProFileEvaluator::aboutToEval(ProFile *, ProFile *, EvalFileType)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::doneWithEval(ProFile *)
|
2009-12-07 22:58:47 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void ProFileEvaluator::logMessage(const QString &message)
|
|
|
|
|
{
|
2009-08-12 13:00:21 +02:00
|
|
|
qWarning("%s", qPrintable(message));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::fileMessage(const QString &message)
|
|
|
|
|
{
|
2009-08-12 13:00:21 +02:00
|
|
|
qWarning("%s", qPrintable(message));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::errorMessage(const QString &message)
|
|
|
|
|
{
|
2009-08-12 13:00:21 +02:00
|
|
|
qWarning("%s", qPrintable(message));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::setVerbose(bool on)
|
|
|
|
|
{
|
|
|
|
|
d->m_verbose = on;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-12 18:10:42 +01:00
|
|
|
void ProFileEvaluator::setCumulative(bool on)
|
|
|
|
|
{
|
|
|
|
|
d->m_cumulative = on;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-12 16:30:31 +01:00
|
|
|
void ProFileEvaluator::setOutputDir(const QString &dir)
|
|
|
|
|
{
|
|
|
|
|
d->m_outputDir = dir;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-02 17:43:43 +01:00
|
|
|
void ProFileEvaluator::setConfigCommandLineArguments(const QStringList &addUserConfigCmdArgs, const QStringList &removeUserConfigCmdArgs)
|
2009-03-19 15:04:43 +01:00
|
|
|
{
|
|
|
|
|
d->m_addUserConfigCmdArgs = addUserConfigCmdArgs;
|
|
|
|
|
d->m_removeUserConfigCmdArgs = removeUserConfigCmdArgs;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-25 16:43:50 +02:00
|
|
|
void ProFileEvaluator::setParsePreAndPostFiles(bool on)
|
|
|
|
|
{
|
|
|
|
|
d->m_parsePreAndPostFiles = on;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QT_END_NAMESPACE
|