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"
|
2010-06-18 19:48:07 +02:00
|
|
|
|
|
|
|
|
#include "profileparser.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-06-18 19:48:07 +02:00
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
2010-02-26 12:53:30 +01:00
|
|
|
# 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
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
using namespace ProStringConstants;
|
|
|
|
|
|
|
|
|
|
|
2009-12-07 22:58:47 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
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
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// ProFileEvaluator::Private
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-06-18 13:30:03 +02:00
|
|
|
#define fL1S(s) QString::fromLatin1(s)
|
|
|
|
|
|
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();
|
2010-06-18 19:48:07 +02:00
|
|
|
Private(ProFileEvaluator *q_, ProFileOption *option, ProFileParser *parser,
|
2010-06-18 13:30:03 +02:00
|
|
|
ProFileEvaluatorHandler *handler);
|
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;
|
|
|
|
|
|
2010-04-29 21:43:41 +02:00
|
|
|
enum VisitReturn {
|
|
|
|
|
ReturnFalse,
|
|
|
|
|
ReturnTrue,
|
|
|
|
|
ReturnBreak,
|
|
|
|
|
ReturnNext,
|
|
|
|
|
ReturnReturn
|
|
|
|
|
};
|
|
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr);
|
|
|
|
|
ProString getStr(const ushort *&tokPtr);
|
|
|
|
|
ProString getHashStr(const ushort *&tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
void evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
|
2010-05-11 12:24:05 +02:00
|
|
|
static ALWAYS_INLINE void skipStr(const ushort *&tokPtr);
|
|
|
|
|
static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
void skipExpression(const ushort *&tokPtr);
|
2010-05-11 12:24:05 +02:00
|
|
|
|
2010-06-18 13:30:03 +02:00
|
|
|
VisitReturn visitProFile(ProFile *pro, ProFileEvaluatorHandler::EvalFileType type);
|
2010-06-23 13:58:44 +02:00
|
|
|
VisitReturn visitProBlock(ProFile *pro, const ushort *tokPtr);
|
2010-05-11 12:24:05 +02:00
|
|
|
VisitReturn visitProBlock(const ushort *tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
VisitReturn visitProLoop(const ProString &variable, const ushort *exprPtr,
|
2010-05-11 12:24:05 +02:00
|
|
|
const ushort *tokPtr);
|
|
|
|
|
void visitProFunctionDef(ushort tok, const ProString &name, const ushort *tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
void visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-06-23 19:32:57 +02:00
|
|
|
static inline const ProString &map(const ProString &var);
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> *findValues(const ProString &variableName,
|
|
|
|
|
QHash<ProString, ProStringList>::Iterator *it);
|
|
|
|
|
ProStringList &valuesRef(const ProString &variableName);
|
|
|
|
|
ProStringList valuesDirect(const ProString &variableName) const;
|
|
|
|
|
ProStringList values(const ProString &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-04-27 18:39:10 +02:00
|
|
|
static ProStringList split_value_list(const QString &vals);
|
2008-12-02 12:01:29 +01:00
|
|
|
bool isActiveConfig(const QString &config, bool regex = false);
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList expandVariableReferences(const ProString &value, int *pos = 0, bool joined = false);
|
2010-05-31 21:07:14 +02:00
|
|
|
ProStringList expandVariableReferences(const ushort *&tokPtr, int sizeHint = 0, bool joined = false);
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList evaluateExpandFunction(const ProString &function, const ProString &arguments);
|
2010-06-01 18:43:11 +02:00
|
|
|
ProStringList evaluateExpandFunction(const ProString &function, const ushort *&tokPtr);
|
|
|
|
|
ProStringList evaluateExpandFunction(const ProString &function, const ProStringList &args);
|
2010-06-18 13:30:03 +02:00
|
|
|
void evalError(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
|
|
|
|
2010-04-29 21:43:41 +02:00
|
|
|
VisitReturn evaluateConditionalFunction(const ProString &function, const ProString &arguments);
|
2010-06-01 18:43:11 +02:00
|
|
|
VisitReturn evaluateConditionalFunction(const ProString &function, const ushort *&tokPtr);
|
|
|
|
|
VisitReturn evaluateConditionalFunction(const ProString &function, const ProStringList &args);
|
2010-06-18 13:30:03 +02:00
|
|
|
bool evaluateFileDirect(const QString &fileName, ProFileEvaluatorHandler::EvalFileType type);
|
|
|
|
|
bool evaluateFile(const QString &fileName, ProFileEvaluatorHandler::EvalFileType type);
|
2010-06-22 12:02:53 +02:00
|
|
|
bool evaluateFeatureFile(const QString &fileName);
|
2010-06-22 12:07:27 +02:00
|
|
|
enum EvalIntoMode { EvalProOnly, EvalWithDefaults, EvalWithSetup };
|
2010-06-18 13:30:03 +02:00
|
|
|
bool evaluateFileInto(const QString &fileName, ProFileEvaluatorHandler::EvalFileType type,
|
2010-06-22 12:07:27 +02:00
|
|
|
QHash<ProString, ProStringList> *values, FunctionDefs *defs,
|
|
|
|
|
EvalIntoMode mode); // values are output-only, defs are input-only
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-05-10 21:24:59 +02:00
|
|
|
static ALWAYS_INLINE VisitReturn returnBool(bool b)
|
2010-04-29 21:43:41 +02:00
|
|
|
{ return b ? ReturnTrue : ReturnFalse; }
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr);
|
2010-04-27 18:39:10 +02:00
|
|
|
QList<ProStringList> prepareFunctionArgs(const ProString &arguments);
|
2010-05-11 12:24:05 +02:00
|
|
|
ProStringList evaluateFunction(const FunctionDef &func, const QList<ProStringList> &argumentsList, bool *ok);
|
2010-05-21 21:18:17 +02:00
|
|
|
VisitReturn evaluateBoolFunction(const FunctionDef &func, const QList<ProStringList> &argumentsList,
|
|
|
|
|
const ProString &function);
|
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
|
|
|
|
2008-12-12 18:10:42 +01:00
|
|
|
int m_skipLevel;
|
2010-04-19 22:35:58 +02:00
|
|
|
int m_loopLevel; // To report unexpected break() and next()s
|
2008-12-12 18:10:42 +01:00
|
|
|
bool m_cumulative;
|
2010-06-23 13:58:44 +02:00
|
|
|
|
|
|
|
|
struct Location {
|
|
|
|
|
Location() : pro(0), line(0) {}
|
|
|
|
|
Location(ProFile *_pro, int _line) : pro(_pro), line(_line) {}
|
|
|
|
|
ProFile *pro;
|
|
|
|
|
int line;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Location m_current; // Currently evaluated location
|
|
|
|
|
QStack<Location> m_locationStack; // All execution location changes
|
|
|
|
|
QStack<ProFile *> m_profileStack; // Includes only
|
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-08-10 17:27:07 +02:00
|
|
|
FunctionDefs m_functionDefs;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList m_returnValue;
|
|
|
|
|
QStack<QHash<ProString, ProStringList> > m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii.
|
|
|
|
|
QHash<const ProFile*, QHash<ProString, ProStringList> > m_filevaluemap; // Variables per include file
|
|
|
|
|
QString m_tmp1, m_tmp2, m_tmp3, m_tmp[2]; // Temporaries for efficient toQString
|
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-06-18 19:48:07 +02:00
|
|
|
ProFileParser *m_parser;
|
2010-06-18 13:30:03 +02:00
|
|
|
ProFileEvaluatorHandler *m_handler;
|
2010-02-08 16:47:25 +01:00
|
|
|
|
|
|
|
|
enum ExpandFunc {
|
2010-04-28 11:37:51 +02:00
|
|
|
E_MEMBER=1, E_FIRST, E_LAST, E_SIZE, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
|
2010-02-08 16:47:25 +01:00
|
|
|
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,
|
2010-04-19 22:35:58 +02:00
|
|
|
T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF
|
2010-02-08 16:47:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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
|
|
|
};
|
|
|
|
|
|
2010-02-08 16:47:25 +01:00
|
|
|
static struct {
|
|
|
|
|
QString field_sep;
|
2010-02-08 17:15:44 +01:00
|
|
|
QString strtrue;
|
|
|
|
|
QString strfalse;
|
|
|
|
|
QString strunix;
|
|
|
|
|
QString strmacx;
|
|
|
|
|
QString strqnx6;
|
|
|
|
|
QString strmac9;
|
|
|
|
|
QString strmac;
|
|
|
|
|
QString strwin32;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString strCONFIG;
|
|
|
|
|
ProString strARGS;
|
2010-02-08 17:15:44 +01:00
|
|
|
QString strDot;
|
|
|
|
|
QString strDotDot;
|
|
|
|
|
QString strever;
|
|
|
|
|
QString strforever;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString strTEMPLATE;
|
|
|
|
|
ProString strQMAKE_DIR_SEP;
|
2010-06-24 13:44:28 +02:00
|
|
|
QHash<ProString, int> expands;
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, int> functions;
|
|
|
|
|
QHash<ProString, int> varList;
|
|
|
|
|
QHash<ProString, ProString> varMap;
|
2010-02-08 17:15:44 +01:00
|
|
|
QRegExp reg_variableName;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList fakeValue;
|
2010-02-08 16:47:25 +01:00
|
|
|
} statics;
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::initStatics()
|
|
|
|
|
{
|
|
|
|
|
if (!statics.field_sep.isNull())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
statics.field_sep = QLatin1String(" ");
|
2010-02-08 17:15:44 +01:00
|
|
|
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");
|
2010-04-27 18:39:10 +02:00
|
|
|
statics.strCONFIG = ProString("CONFIG");
|
|
|
|
|
statics.strARGS = ProString("ARGS");
|
2010-02-08 17:15:44 +01:00
|
|
|
statics.strDot = QLatin1String(".");
|
|
|
|
|
statics.strDotDot = QLatin1String("..");
|
|
|
|
|
statics.strever = QLatin1String("ever");
|
|
|
|
|
statics.strforever = QLatin1String("forever");
|
2010-04-27 18:39:10 +02:00
|
|
|
statics.strTEMPLATE = ProString("TEMPLATE");
|
|
|
|
|
statics.strQMAKE_DIR_SEP = ProString("QMAKE_DIR_SEP");
|
2010-02-08 17:15:44 +01:00
|
|
|
|
|
|
|
|
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 },
|
2010-04-28 11:37:51 +02:00
|
|
|
{ "size", E_SIZE },
|
2010-02-08 16:47:25 +01:00
|
|
|
{ "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)
|
2010-06-24 13:44:28 +02:00
|
|
|
statics.expands.insert(ProString(expandInits[i].name), expandInits[i].func);
|
2010-02-08 16:47:25 +01:00
|
|
|
|
|
|
|
|
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 (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i)
|
2010-04-27 18:39:10 +02:00
|
|
|
statics.functions.insert(ProString(testInits[i].name), testInits[i].func);
|
2010-02-08 16:47:25 +01:00
|
|
|
|
|
|
|
|
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)
|
2010-04-27 18:39:10 +02:00
|
|
|
statics.varList.insert(ProString(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)
|
2010-04-27 18:39:10 +02:00
|
|
|
statics.varMap.insert(ProString(mapInits[i].oldname),
|
|
|
|
|
ProString(mapInits[i].newname));
|
2010-02-11 16:33:16 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-23 19:32:57 +02:00
|
|
|
const ProString &ProFileEvaluator::Private::map(const ProString &var)
|
2010-02-11 16:33:16 +01:00
|
|
|
{
|
2010-06-23 19:32:57 +02:00
|
|
|
QHash<ProString, ProString>::ConstIterator it = statics.varMap.constFind(var);
|
|
|
|
|
return (it != statics.varMap.constEnd()) ? it.value() : var;
|
2010-02-08 16:47:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-18 13:30:03 +02:00
|
|
|
ProFileEvaluator::Private::Private(ProFileEvaluator *q_, ProFileOption *option,
|
2010-06-18 19:48:07 +02:00
|
|
|
ProFileParser *parser, ProFileEvaluatorHandler *handler)
|
|
|
|
|
: q(q_), m_option(option), m_parser(parser), m_handler(handler)
|
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-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
|
2008-12-12 18:10:42 +01:00
|
|
|
m_skipLevel = 0;
|
2010-04-19 22:35:58 +02:00
|
|
|
m_loopLevel = 0;
|
2010-02-08 16:51:50 +01:00
|
|
|
m_listCount = 0;
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.push(QHash<ProString, ProStringList>());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-08-10 17:27:07 +02:00
|
|
|
ProFileEvaluator::Private::~Private()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
//////// Evaluator tools /////////
|
|
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
uint ProFileEvaluator::Private::getBlockLen(const ushort *&tokPtr)
|
|
|
|
|
{
|
|
|
|
|
uint len = *tokPtr++;
|
|
|
|
|
len |= (uint)*tokPtr++ << 16;
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProString ProFileEvaluator::Private::getStr(const ushort *&tokPtr)
|
|
|
|
|
{
|
|
|
|
|
uint len = *tokPtr++;
|
2010-06-23 14:51:43 +02:00
|
|
|
ProString ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len, NoHash);
|
2010-05-11 12:24:05 +02:00
|
|
|
tokPtr += len;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProString ProFileEvaluator::Private::getHashStr(const ushort *&tokPtr)
|
|
|
|
|
{
|
|
|
|
|
uint hash = getBlockLen(tokPtr);
|
|
|
|
|
uint len = *tokPtr++;
|
2010-06-23 14:51:43 +02:00
|
|
|
ProString ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len, hash);
|
2010-05-11 12:24:05 +02:00
|
|
|
tokPtr += len;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::skipStr(const ushort *&tokPtr)
|
|
|
|
|
{
|
|
|
|
|
uint len = *tokPtr++;
|
|
|
|
|
tokPtr += len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::skipHashStr(const ushort *&tokPtr)
|
|
|
|
|
{
|
|
|
|
|
tokPtr += 2;
|
|
|
|
|
uint len = *tokPtr++;
|
|
|
|
|
tokPtr += len;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
// FIXME: this should not build new strings for direct sections.
|
|
|
|
|
// Note that the E_SPRINTF and E_LIST implementations rely on the deep copy.
|
|
|
|
|
ProStringList ProFileEvaluator::Private::split_value_list(const QString &vals)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
|
|
|
|
QString build;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ret;
|
2009-07-23 16:34:30 +02:00
|
|
|
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) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ret << ProString(build, NoHash);
|
2009-07-23 16:34:30 +02:00
|
|
|
build.clear();
|
|
|
|
|
} else {
|
|
|
|
|
build += vals_data[x];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!build.isEmpty())
|
2010-04-27 18:39:10 +02:00
|
|
|
ret << ProString(build, NoHash);
|
2009-07-23 16:34:30 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-27 20:21:01 +02:00
|
|
|
static void zipEmpty(ProStringList *value)
|
|
|
|
|
{
|
|
|
|
|
for (int i = value->size(); --i >= 0;)
|
|
|
|
|
if (value->at(i).isEmpty())
|
|
|
|
|
value->remove(i);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void insertUnique(ProStringList *varlist, const ProStringList &value)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
foreach (const ProString &str, value)
|
2010-05-27 20:21:01 +02:00
|
|
|
if (!str.isEmpty() && !varlist->contains(str))
|
2010-02-09 15:44:17 +01:00
|
|
|
varlist->append(str);
|
2009-07-23 16:34:30 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void removeAll(ProStringList *varlist, const ProString &value)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
for (int i = varlist->size(); --i >= 0; )
|
|
|
|
|
if (varlist->at(i) == value)
|
|
|
|
|
varlist->remove(i);
|
2009-07-23 16:34:30 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void removeEach(ProStringList *varlist, const ProStringList &value)
|
2009-07-23 16:34:30 +02:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
foreach (const ProString &str, value)
|
2010-05-27 20:21:01 +02:00
|
|
|
if (!str.isEmpty())
|
|
|
|
|
removeAll(varlist, str);
|
2010-04-27 18:39:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void replaceInList(ProStringList *varlist,
|
|
|
|
|
const QRegExp ®exp, const QString &replace, bool global, QString &tmp)
|
|
|
|
|
{
|
|
|
|
|
for (ProStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
|
|
|
|
|
QString val = varit->toQString(tmp);
|
|
|
|
|
QString copy = val; // Force detach and have a reference value
|
|
|
|
|
val.replace(regexp, replace);
|
|
|
|
|
if (!val.isSharedWith(copy)) {
|
|
|
|
|
if (val.isEmpty()) {
|
2009-07-23 16:34:30 +02:00
|
|
|
varit = varlist->erase(varit);
|
2010-04-27 18:39:10 +02:00
|
|
|
} else {
|
|
|
|
|
*varit = ProString(val);
|
2009-07-23 16:34:30 +02:00
|
|
|
++varit;
|
2010-04-27 18:39:10 +02:00
|
|
|
}
|
2009-07-23 16:34:30 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static bool isTrue(const ProString &_str, QString &tmp)
|
2010-04-29 17:46:57 +02:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &str = _str.toQString(tmp);
|
2010-04-29 17:46:57 +02:00
|
|
|
return !str.compare(statics.strtrue, Qt::CaseInsensitive) || str.toInt();
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-23 16:34:30 +02:00
|
|
|
//////// Evaluator /////////
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
static ALWAYS_INLINE void addStr(
|
|
|
|
|
const ProString &str, ProStringList *ret, bool &pending, bool joined)
|
|
|
|
|
{
|
|
|
|
|
if (joined) {
|
|
|
|
|
ret->last().append(str, &pending);
|
|
|
|
|
} else {
|
|
|
|
|
if (!pending) {
|
|
|
|
|
pending = true;
|
|
|
|
|
*ret << str;
|
|
|
|
|
} else {
|
|
|
|
|
ret->last().append(str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ALWAYS_INLINE void addStrList(
|
|
|
|
|
const ProStringList &list, ushort tok, ProStringList *ret, bool &pending, bool joined)
|
|
|
|
|
{
|
|
|
|
|
if (!list.isEmpty()) {
|
|
|
|
|
if (joined) {
|
|
|
|
|
ret->last().append(list, &pending, !(tok & TokQuoted));
|
|
|
|
|
} else {
|
|
|
|
|
if (tok & TokQuoted) {
|
|
|
|
|
if (!pending) {
|
|
|
|
|
pending = true;
|
|
|
|
|
*ret << ProString();
|
|
|
|
|
}
|
|
|
|
|
ret->last().append(list);
|
|
|
|
|
} else {
|
|
|
|
|
if (!pending) {
|
|
|
|
|
// Another qmake bizzarity: if nothing is pending and the
|
|
|
|
|
// first element is empty, it will be eaten
|
|
|
|
|
if (!list.at(0).isEmpty()) {
|
|
|
|
|
// The common case
|
2010-06-24 14:49:35 +02:00
|
|
|
pending = true;
|
2010-06-01 18:43:11 +02:00
|
|
|
*ret += list;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ret->last().append(list.at(0));
|
|
|
|
|
}
|
|
|
|
|
// This is somewhat slow, but a corner case
|
2010-06-24 14:49:35 +02:00
|
|
|
for (int j = 1; j < list.size(); ++j) {
|
|
|
|
|
pending = true;
|
2010-06-01 18:43:11 +02:00
|
|
|
*ret << list.at(j);
|
2010-06-24 14:49:35 +02:00
|
|
|
}
|
2010-06-01 18:43:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::evaluateExpression(
|
|
|
|
|
const ushort *&tokPtr, ProStringList *ret, bool joined)
|
|
|
|
|
{
|
|
|
|
|
if (joined)
|
|
|
|
|
*ret << ProString();
|
|
|
|
|
bool pending = false;
|
|
|
|
|
forever {
|
|
|
|
|
ushort tok = *tokPtr++;
|
|
|
|
|
if (tok & TokNewStr)
|
|
|
|
|
pending = false;
|
|
|
|
|
ushort maskedTok = tok & TokMask;
|
|
|
|
|
switch (maskedTok) {
|
|
|
|
|
case TokLine:
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current.line = *tokPtr++;
|
2010-06-01 18:43:11 +02:00
|
|
|
break;
|
|
|
|
|
case TokLiteral:
|
|
|
|
|
addStr(getStr(tokPtr), ret, pending, joined);
|
|
|
|
|
break;
|
|
|
|
|
case TokHashLiteral:
|
|
|
|
|
addStr(getHashStr(tokPtr), ret, pending, joined);
|
|
|
|
|
break;
|
|
|
|
|
case TokVariable:
|
|
|
|
|
addStrList(values(map(getHashStr(tokPtr))), tok, ret, pending, joined);
|
|
|
|
|
break;
|
|
|
|
|
case TokProperty:
|
|
|
|
|
addStr(ProString(propertyValue(
|
|
|
|
|
getStr(tokPtr).toQString(m_tmp1)), NoHash), ret, pending, joined);
|
|
|
|
|
break;
|
|
|
|
|
case TokEnvVar:
|
|
|
|
|
addStrList(split_value_list(QString::fromLocal8Bit(qgetenv(
|
|
|
|
|
getStr(tokPtr).toQString(m_tmp1).toLatin1().constData()))), tok, ret, pending, joined);
|
|
|
|
|
break;
|
|
|
|
|
case TokFuncName: {
|
|
|
|
|
ProString func = getHashStr(tokPtr);
|
|
|
|
|
addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined);
|
|
|
|
|
break; }
|
|
|
|
|
default:
|
|
|
|
|
tokPtr--;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProFileEvaluator::Private::skipExpression(const ushort *&pTokPtr)
|
|
|
|
|
{
|
|
|
|
|
const ushort *tokPtr = pTokPtr;
|
|
|
|
|
forever {
|
|
|
|
|
ushort tok = *tokPtr++;
|
|
|
|
|
switch (tok) {
|
|
|
|
|
case TokLine:
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current.line = *tokPtr++;
|
2010-06-01 18:43:11 +02:00
|
|
|
break;
|
|
|
|
|
case TokValueTerminator:
|
|
|
|
|
case TokFuncTerminator:
|
|
|
|
|
pTokPtr = tokPtr;
|
|
|
|
|
return;
|
|
|
|
|
case TokArgSeparator:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
switch (tok & TokMask) {
|
|
|
|
|
case TokLiteral:
|
|
|
|
|
case TokProperty:
|
|
|
|
|
case TokEnvVar:
|
|
|
|
|
skipStr(tokPtr);
|
|
|
|
|
break;
|
|
|
|
|
case TokHashLiteral:
|
|
|
|
|
case TokVariable:
|
|
|
|
|
skipHashStr(tokPtr);
|
|
|
|
|
break;
|
|
|
|
|
case TokFuncName:
|
|
|
|
|
skipHashStr(tokPtr);
|
|
|
|
|
pTokPtr = tokPtr;
|
|
|
|
|
skipExpression(pTokPtr);
|
|
|
|
|
tokPtr = pTokPtr;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
Q_ASSERT_X(false, "skipExpression", "Unrecognized token");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-23 13:58:44 +02:00
|
|
|
ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProBlock(
|
|
|
|
|
ProFile *pro, const ushort *tokPtr)
|
|
|
|
|
{
|
|
|
|
|
m_current.pro = pro;
|
|
|
|
|
m_current.line = 0;
|
|
|
|
|
return visitProBlock(tokPtr);
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProBlock(
|
|
|
|
|
const ushort *tokPtr)
|
2010-02-02 21:00:09 +01:00
|
|
|
{
|
2010-06-01 18:43:11 +02:00
|
|
|
ProStringList curr;
|
2010-04-19 22:35:58 +02:00
|
|
|
bool okey = true, or_op = false, invert = false;
|
2010-05-11 12:24:05 +02:00
|
|
|
uint blockLen;
|
2010-04-29 21:43:41 +02:00
|
|
|
VisitReturn ret = ReturnTrue;
|
2010-05-11 12:24:05 +02:00
|
|
|
while (ushort tok = *tokPtr++) {
|
|
|
|
|
switch (tok) {
|
|
|
|
|
case TokLine:
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current.line = *tokPtr++;
|
2010-04-19 22:35:58 +02:00
|
|
|
continue;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokAssign:
|
|
|
|
|
case TokAppend:
|
|
|
|
|
case TokAppendUnique:
|
|
|
|
|
case TokRemove:
|
2010-06-01 18:43:11 +02:00
|
|
|
case TokReplace:
|
|
|
|
|
visitProVariable(tok, curr, tokPtr);
|
|
|
|
|
curr.clear();
|
|
|
|
|
continue;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokBranch:
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (m_cumulative) {
|
|
|
|
|
if (!okey)
|
|
|
|
|
m_skipLevel++;
|
2010-05-11 12:24:05 +02:00
|
|
|
ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
|
|
|
|
|
tokPtr += blockLen;
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (!okey)
|
|
|
|
|
m_skipLevel--;
|
|
|
|
|
else
|
|
|
|
|
m_skipLevel++;
|
2010-05-11 12:24:05 +02:00
|
|
|
if ((ret == ReturnTrue || ret == ReturnFalse) && blockLen)
|
|
|
|
|
ret = visitProBlock(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (okey)
|
|
|
|
|
m_skipLevel--;
|
|
|
|
|
} else {
|
2010-05-11 12:24:05 +02:00
|
|
|
if (okey)
|
|
|
|
|
ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
|
|
|
|
|
tokPtr += blockLen;
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
if (!okey)
|
|
|
|
|
ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
2010-05-11 12:24:05 +02:00
|
|
|
tokPtr += blockLen;
|
2010-04-19 22:35:58 +02:00
|
|
|
okey = true, or_op = false; // force next evaluation
|
|
|
|
|
break;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokForLoop:
|
|
|
|
|
if (m_cumulative) { // This is a no-win situation, so just pretend it's no loop
|
|
|
|
|
skipHashStr(tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
uint exprLen = getBlockLen(tokPtr);
|
|
|
|
|
tokPtr += exprLen;
|
2010-05-11 12:24:05 +02:00
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
ret = visitProBlock(tokPtr);
|
|
|
|
|
} else if (okey != or_op) {
|
|
|
|
|
const ProString &variable = getHashStr(tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
uint exprLen = getBlockLen(tokPtr);
|
|
|
|
|
const ushort *exprPtr = tokPtr;
|
|
|
|
|
tokPtr += exprLen;
|
2010-05-11 12:24:05 +02:00
|
|
|
blockLen = getBlockLen(tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
ret = visitProLoop(variable, exprPtr, tokPtr);
|
2010-05-11 12:24:05 +02:00
|
|
|
} else {
|
|
|
|
|
skipHashStr(tokPtr);
|
2010-06-01 18:43:11 +02:00
|
|
|
uint exprLen = getBlockLen(tokPtr);
|
|
|
|
|
tokPtr += exprLen;
|
2010-05-11 12:24:05 +02:00
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
ret = ReturnTrue;
|
|
|
|
|
}
|
|
|
|
|
tokPtr += blockLen;
|
2010-04-19 22:35:58 +02:00
|
|
|
okey = true, or_op = false; // force next evaluation
|
|
|
|
|
break;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokTestDef:
|
|
|
|
|
case TokReplaceDef:
|
|
|
|
|
if (m_cumulative || okey != or_op) {
|
|
|
|
|
const ProString &name = getHashStr(tokPtr);
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
visitProFunctionDef(tok, name, tokPtr);
|
|
|
|
|
} else {
|
|
|
|
|
skipHashStr(tokPtr);
|
|
|
|
|
blockLen = getBlockLen(tokPtr);
|
|
|
|
|
}
|
|
|
|
|
tokPtr += blockLen;
|
2010-04-19 22:35:58 +02:00
|
|
|
okey = true, or_op = false; // force next evaluation
|
|
|
|
|
continue;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokNot:
|
2010-04-19 22:35:58 +02:00
|
|
|
invert ^= true;
|
2010-05-11 12:24:05 +02:00
|
|
|
continue;
|
|
|
|
|
case TokAnd:
|
2010-04-19 22:35:58 +02:00
|
|
|
or_op = false;
|
2010-05-11 12:24:05 +02:00
|
|
|
continue;
|
|
|
|
|
case TokOr:
|
2010-04-19 22:35:58 +02:00
|
|
|
or_op = true;
|
2010-05-11 12:24:05 +02:00
|
|
|
continue;
|
|
|
|
|
case TokCondition:
|
2010-04-19 22:35:58 +02:00
|
|
|
if (!m_skipLevel && okey != or_op) {
|
2010-06-01 18:43:11 +02:00
|
|
|
if (curr.size() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Conditional must expand to exactly one word."));
|
2010-06-01 18:43:11 +02:00
|
|
|
okey = false;
|
|
|
|
|
} else {
|
|
|
|
|
okey = isActiveConfig(curr.at(0).toQString(m_tmp2), true) ^ invert;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
or_op = !okey; // tentatively force next evaluation
|
|
|
|
|
invert = false;
|
|
|
|
|
curr.clear();
|
|
|
|
|
continue;
|
|
|
|
|
case TokTestCall:
|
|
|
|
|
if (!m_skipLevel && okey != or_op) {
|
|
|
|
|
if (curr.size() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Test name must expand to exactly one word."));
|
2010-06-01 18:43:11 +02:00
|
|
|
skipExpression(tokPtr);
|
|
|
|
|
okey = false;
|
|
|
|
|
} else {
|
|
|
|
|
ret = evaluateConditionalFunction(curr.at(0), tokPtr);
|
|
|
|
|
switch (ret) {
|
|
|
|
|
case ReturnTrue: okey = true; break;
|
|
|
|
|
case ReturnFalse: okey = false; break;
|
|
|
|
|
default: return ret;
|
|
|
|
|
}
|
|
|
|
|
okey ^= invert;
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
|
|
|
|
} else if (m_cumulative) {
|
|
|
|
|
m_skipLevel++;
|
2010-06-01 18:43:11 +02:00
|
|
|
if (curr.size() != 1)
|
|
|
|
|
skipExpression(tokPtr);
|
|
|
|
|
else
|
|
|
|
|
evaluateConditionalFunction(curr.at(0), tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
m_skipLevel--;
|
2010-05-11 12:24:05 +02:00
|
|
|
} else {
|
2010-06-01 18:43:11 +02:00
|
|
|
skipExpression(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
|
|
|
|
or_op = !okey; // tentatively force next evaluation
|
|
|
|
|
invert = false;
|
2010-06-01 18:43:11 +02:00
|
|
|
curr.clear();
|
2010-05-11 12:24:05 +02:00
|
|
|
continue;
|
2010-06-01 18:43:11 +02:00
|
|
|
default: {
|
|
|
|
|
const ushort *oTokPtr = --tokPtr;
|
|
|
|
|
evaluateExpression(tokPtr, &curr, false);
|
|
|
|
|
if (tokPtr != oTokPtr)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Q_ASSERT_X(false, "visitProBlock", "unexpected item type");
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
2010-04-29 21:43:41 +02:00
|
|
|
if (ret != ReturnTrue && ret != ReturnFalse)
|
2010-04-19 22:35:58 +02:00
|
|
|
break;
|
2010-02-02 21:00:09 +01:00
|
|
|
}
|
2010-04-19 22:35:58 +02:00
|
|
|
return ret;
|
2010-02-02 21:00:09 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-19 22:35:58 +02:00
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
void ProFileEvaluator::Private::visitProFunctionDef(
|
|
|
|
|
ushort tok, const ProString &name, const ushort *tokPtr)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-05-11 12:24:05 +02:00
|
|
|
QHash<ProString, FunctionDef> *hash =
|
|
|
|
|
(tok == TokTestDef
|
2010-04-19 22:35:58 +02:00
|
|
|
? &m_functionDefs.testFunctions
|
|
|
|
|
: &m_functionDefs.replaceFunctions);
|
2010-06-23 14:51:43 +02:00
|
|
|
hash->insert(name, FunctionDef(m_current.pro, tokPtr - m_current.pro->tokPtr()));
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProLoop(
|
2010-06-01 18:43:11 +02:00
|
|
|
const ProString &_variable, const ushort *exprPtr, const ushort *tokPtr)
|
2010-04-19 22:35:58 +02:00
|
|
|
{
|
2010-04-29 21:43:41 +02:00
|
|
|
VisitReturn ret = ReturnTrue;
|
2010-04-19 22:35:58 +02:00
|
|
|
bool infinite = false;
|
|
|
|
|
int index = 0;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString variable;
|
|
|
|
|
ProStringList oldVarVal;
|
2010-05-31 21:07:14 +02:00
|
|
|
ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0);
|
2010-05-11 12:24:05 +02:00
|
|
|
if (_variable.isEmpty()) {
|
2010-04-19 22:35:58 +02:00
|
|
|
if (it_list != statics.strever) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Invalid loop expression."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
it_list = ProString(statics.strforever);
|
2009-05-14 14:35:37 +02:00
|
|
|
} else {
|
2010-05-11 12:24:05 +02:00
|
|
|
variable = map(_variable);
|
2010-04-19 22:35:58 +02:00
|
|
|
oldVarVal = valuesDirect(variable);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList list = valuesDirect(it_list);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (list.isEmpty()) {
|
|
|
|
|
if (it_list == statics.strforever) {
|
|
|
|
|
infinite = true;
|
|
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &itl = it_list.toQString(m_tmp1);
|
|
|
|
|
int dotdot = itl.indexOf(statics.strDotDot);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (dotdot != -1) {
|
|
|
|
|
bool ok;
|
2010-04-27 18:39:10 +02:00
|
|
|
int start = itl.left(dotdot).toInt(&ok);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (ok) {
|
2010-04-27 18:39:10 +02:00
|
|
|
int end = itl.mid(dotdot+2).toInt(&ok);
|
2010-04-19 22:35:58 +02:00
|
|
|
if (ok) {
|
|
|
|
|
if (start < end) {
|
|
|
|
|
for (int i = start; i <= end; i++)
|
2010-04-27 18:39:10 +02:00
|
|
|
list << ProString(QString::number(i), NoHash);
|
2010-04-19 22:35:58 +02:00
|
|
|
} else {
|
|
|
|
|
for (int i = start; i >= end; i--)
|
2010-04-27 18:39:10 +02:00
|
|
|
list << ProString(QString::number(i), NoHash);
|
2010-02-02 21:00:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
2010-02-02 21:00:09 +01:00
|
|
|
}
|
2008-12-16 10:48:49 +01:00
|
|
|
}
|
2008-12-12 18:10:42 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-04-19 22:35:58 +02:00
|
|
|
m_loopLevel++;
|
|
|
|
|
forever {
|
|
|
|
|
if (infinite) {
|
|
|
|
|
if (!variable.isEmpty())
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index++), NoHash));
|
2010-04-19 22:35:58 +02:00
|
|
|
if (index > 1000) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("ran into infinite loop (> 1000 iterations)."));
|
2010-04-19 22:35:58 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString val;
|
2010-04-19 22:35:58 +02:00
|
|
|
do {
|
|
|
|
|
if (index >= list.count())
|
|
|
|
|
goto do_break;
|
|
|
|
|
val = list.at(index++);
|
|
|
|
|
} while (val.isEmpty()); // stupid, but qmake is like that
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.top()[variable] = ProStringList(val);
|
2010-04-19 22:35:58 +02:00
|
|
|
}
|
2009-05-19 19:00:06 +02:00
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
ret = visitProBlock(tokPtr);
|
2010-04-19 22:35:58 +02:00
|
|
|
switch (ret) {
|
2010-04-29 21:43:41 +02:00
|
|
|
case ReturnTrue:
|
|
|
|
|
case ReturnFalse:
|
2010-04-19 22:35:58 +02:00
|
|
|
break;
|
2010-04-29 21:43:41 +02:00
|
|
|
case ReturnNext:
|
|
|
|
|
ret = ReturnTrue;
|
2010-04-19 22:35:58 +02:00
|
|
|
break;
|
2010-04-29 21:43:41 +02:00
|
|
|
case ReturnBreak:
|
|
|
|
|
ret = ReturnTrue;
|
2010-04-19 22:35:58 +02:00
|
|
|
goto do_break;
|
|
|
|
|
default:
|
|
|
|
|
goto do_break;
|
2009-05-19 19:00:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-04-19 22:35:58 +02:00
|
|
|
do_break:
|
|
|
|
|
m_loopLevel--;
|
2009-05-19 19:00:06 +02:00
|
|
|
|
2010-04-19 22:35:58 +02:00
|
|
|
if (!variable.isEmpty())
|
|
|
|
|
m_valuemapStack.top()[variable] = oldVarVal;
|
|
|
|
|
return ret;
|
2009-05-19 19:00:06 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
void ProFileEvaluator::Private::visitProVariable(
|
2010-06-01 18:43:11 +02:00
|
|
|
ushort tok, const ProStringList &curr, const ushort *&tokPtr)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-05-31 21:07:14 +02:00
|
|
|
int sizeHint = *tokPtr++;
|
|
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
if (curr.size() != 1) {
|
|
|
|
|
skipExpression(tokPtr);
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Left hand side of assignment must expand to exactly one word."));
|
2010-06-01 18:43:11 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const ProString &varName = map(curr.first());
|
|
|
|
|
|
2010-05-11 12:24:05 +02:00
|
|
|
if (tok == TokReplace) { // ~=
|
2010-01-14 12:34:46 +01:00
|
|
|
// DEFINES ~= s/a/b/?[gqi]
|
2009-07-14 20:42:45 +02:00
|
|
|
|
2010-05-31 21:07:14 +02:00
|
|
|
const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true);
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &val = varVal.at(0).toQString(m_tmp1);
|
2010-01-14 12:34:46 +01:00
|
|
|
if (val.length() < 4 || val.at(0) != QLatin1Char('s')) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("the ~= operator can handle only the s/// function."));
|
2010-01-14 12:34:46 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
QChar sep = val.at(1);
|
|
|
|
|
QStringList func = val.split(sep);
|
|
|
|
|
if (func.count() < 3 || func.count() > 4) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("the s/// function expects 3 or 4 arguments."));
|
2010-01-14 12:34:46 +01:00
|
|
|
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-04-27 18:39:10 +02:00
|
|
|
replaceInList(&valuesRef(varName), regexp, replace, global, m_tmp2);
|
|
|
|
|
replaceInList(&m_filevaluemap[currentProFile()][varName], regexp, replace, global, m_tmp2);
|
2010-01-14 12:34:46 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
2010-05-31 21:07:14 +02:00
|
|
|
ProStringList varVal = expandVariableReferences(tokPtr, sizeHint);
|
2010-05-11 12:24:05 +02:00
|
|
|
switch (tok) {
|
|
|
|
|
default: // whatever - cannot happen
|
|
|
|
|
case TokAssign: // =
|
2009-07-14 20:42:45 +02:00
|
|
|
if (!m_cumulative) {
|
|
|
|
|
if (!m_skipLevel) {
|
2010-05-27 20:21:01 +02:00
|
|
|
zipEmpty(&varVal);
|
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 {
|
2010-05-27 20:21:01 +02:00
|
|
|
zipEmpty(&varVal);
|
2010-06-24 15:17:28 +02:00
|
|
|
if (!varVal.isEmpty()) {
|
|
|
|
|
// We are greedy for values. But avoid exponential growth.
|
|
|
|
|
ProStringList &v = valuesRef(varName);
|
|
|
|
|
if (v.isEmpty()) {
|
|
|
|
|
v = varVal;
|
|
|
|
|
} else {
|
|
|
|
|
ProStringList old = v;
|
|
|
|
|
v = varVal;
|
|
|
|
|
QSet<ProString> has;
|
|
|
|
|
has.reserve(v.size());
|
|
|
|
|
foreach (const ProString &s, v)
|
|
|
|
|
has.insert(s);
|
|
|
|
|
v.reserve(v.size() + old.size());
|
|
|
|
|
foreach (const ProString &s, old)
|
|
|
|
|
if (!has.contains(s))
|
|
|
|
|
v << s;
|
|
|
|
|
}
|
|
|
|
|
// These values will not be used for further processing inside
|
|
|
|
|
// the evaluator. Duplicate elimination happens later.
|
|
|
|
|
m_filevaluemap[currentProFile()][varName] += varVal;
|
2010-06-24 11:03:52 +02:00
|
|
|
}
|
2009-07-14 20:42:45 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokAppendUnique: // *=
|
2009-07-14 20:42:45 +02:00
|
|
|
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;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokAppend: // +=
|
2009-07-14 20:42:45 +02:00
|
|
|
if (!m_skipLevel || m_cumulative) {
|
2010-05-27 20:21:01 +02:00
|
|
|
zipEmpty(&varVal);
|
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;
|
2010-05-11 12:24:05 +02:00
|
|
|
case TokRemove: // -=
|
2009-07-14 20:42:45 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2010-06-18 20:39:45 +02:00
|
|
|
ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProFile(
|
2010-06-18 13:30:03 +02:00
|
|
|
ProFile *pro, ProFileEvaluatorHandler::EvalFileType type)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-06-18 13:30:03 +02:00
|
|
|
m_handler->aboutToEval(currentProFile(), pro, type);
|
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
|
|
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
bool cumulative = m_cumulative;
|
|
|
|
|
m_cumulative = false;
|
|
|
|
|
|
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);
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> cache_valuemap;
|
2010-06-18 13:30:03 +02:00
|
|
|
if (evaluateFileInto(qmake_cache, ProFileEvaluatorHandler::EvalConfigFile,
|
2010-06-22 12:07:27 +02:00
|
|
|
&cache_valuemap, 0, EvalProOnly)) {
|
2009-08-04 16:16:27 +02:00
|
|
|
if (m_option->qmakespec.isEmpty()) {
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProStringList &vals = cache_valuemap.value(ProString("QMAKESPEC"));
|
2009-08-04 16:16:27 +02:00
|
|
|
if (!vals.isEmpty())
|
2010-04-27 18:39:10 +02:00
|
|
|
m_option->qmakespec = vals.first().toQString();
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
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()) {
|
2010-06-18 13:30:03 +02:00
|
|
|
m_handler->configError(fL1S("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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-18 13:30:03 +02:00
|
|
|
m_handler->configError(fL1S("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");
|
2010-06-22 12:02:53 +02:00
|
|
|
if (!evaluateFileDirect(spec, ProFileEvaluatorHandler::EvalConfigFile)) {
|
2010-06-18 13:30:03 +02:00
|
|
|
m_handler->configError(
|
|
|
|
|
fL1S("Could not read qmake configuration file %1").arg(spec));
|
2009-09-08 14:19:34 +02:00
|
|
|
} else if (!m_option->cachefile.isEmpty()) {
|
2010-06-22 12:02:53 +02:00
|
|
|
evaluateFileDirect(m_option->cachefile, ProFileEvaluatorHandler::EvalConfigFile);
|
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.
|
2010-06-02 21:51:27 +02:00
|
|
|
const ProStringList &spec_org =
|
|
|
|
|
m_option->base_valuemap.value(ProString("QMAKESPEC_ORIGINAL"));
|
2010-02-10 15:35:57 +01:00
|
|
|
if (!spec_org.isEmpty())
|
|
|
|
|
m_option->qmakespec_name =
|
2010-06-02 21:51:27 +02:00
|
|
|
IoUtils::fileName(spec_org.first().toQString()).toString();
|
2010-02-10 15:35:57 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
evaluateFeatureFile(QLatin1String("default_pre.prf"));
|
|
|
|
|
|
|
|
|
|
m_option->base_valuemap = m_valuemapStack.top();
|
|
|
|
|
m_option->base_functions = m_functionDefs;
|
|
|
|
|
|
|
|
|
|
m_cumulative = cumulative;
|
2010-06-04 17:08:27 +02:00
|
|
|
|
|
|
|
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
|
|
|
|
locker.relock();
|
|
|
|
|
m_option->base_inProgress = false;
|
|
|
|
|
m_option->cond.wakeAll();
|
|
|
|
|
#endif
|
2010-06-22 12:02:53 +02:00
|
|
|
goto fresh;
|
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-08-10 17:27:07 +02:00
|
|
|
m_functionDefs = m_option->base_functions;
|
|
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
fresh:
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList &tgt = m_valuemapStack.top()[ProString("TARGET")];
|
2009-07-29 11:30:33 +02:00
|
|
|
if (tgt.isEmpty())
|
2010-04-27 18:39:10 +02:00
|
|
|
tgt.append(ProString(QFileInfo(pro->fileName()).baseName(), NoHash));
|
2009-07-29 11:30:33 +02:00
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList &tmp = m_valuemapStack.top()[ProString("CONFIG")];
|
|
|
|
|
foreach (const QString &add, m_addUserConfigCmdArgs)
|
|
|
|
|
tmp.append(ProString(add, NoHash));
|
2009-07-22 11:03:01 +02:00
|
|
|
foreach (const QString &remove, m_removeUserConfigCmdArgs)
|
2010-04-27 18:39:10 +02:00
|
|
|
removeAll(&tmp, ProString(remove, NoHash));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-23 14:51:43 +02:00
|
|
|
visitProBlock(pro, pro->tokPtr());
|
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-04-27 18:39:10 +02:00
|
|
|
ProStringList configs = valuesDirect(statics.strCONFIG);
|
2009-07-22 11:03:01 +02:00
|
|
|
for (int i = configs.size() - 1; i >= 0; --i) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QString config = configs.at(i).toQString(m_tmp1).toLower();
|
2009-07-22 11:03:01 +02:00
|
|
|
if (!processed.contains(config)) {
|
2010-04-27 18:39:10 +02:00
|
|
|
config.detach();
|
2009-07-22 11:03:01 +02:00
|
|
|
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-06-18 13:30:03 +02:00
|
|
|
m_handler->doneWithEval(currentProFile());
|
2009-07-22 17:46:25 +02:00
|
|
|
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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)
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("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
|
|
|
}
|
|
|
|
|
|
2010-01-14 18:02:22 +01:00
|
|
|
// The (QChar*)current->constData() constructs below avoid pointless detach() calls
|
2010-04-27 18:39:10 +02:00
|
|
|
// FIXME: This is inefficient. Should not make new string if it is a straight subsegment
|
2010-05-10 21:24:59 +02:00
|
|
|
static ALWAYS_INLINE void appendChar(ushort unicode,
|
2010-04-27 18:39:10 +02:00
|
|
|
QString *current, QChar **ptr, ProString *pending)
|
2010-01-14 18:02:22 +01:00
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void appendString(const ProString &string,
|
|
|
|
|
QString *current, QChar **ptr, ProString *pending)
|
2010-01-14 18:02:22 +01:00
|
|
|
{
|
|
|
|
|
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;
|
2010-04-27 18:39:10 +02:00
|
|
|
::memcpy(*ptr, string.constData(), string.size() * 2);
|
2010-01-14 18:02:22 +01:00
|
|
|
*ptr += string.size();
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static void flushCurrent(ProStringList *ret,
|
|
|
|
|
QString *current, QChar **ptr, ProString *pending, bool joined)
|
2010-01-14 18:02:22 +01:00
|
|
|
{
|
|
|
|
|
QChar *uc = (QChar*)current->constData();
|
|
|
|
|
int len = *ptr - uc;
|
|
|
|
|
if (len) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ret->append(ProString(QString(uc, len), NoHash));
|
2010-01-14 18:02:22 +01:00
|
|
|
*ptr = uc;
|
|
|
|
|
} else if (!pending->isEmpty()) {
|
|
|
|
|
ret->append(*pending);
|
|
|
|
|
pending->clear();
|
2010-04-27 22:00:11 +02:00
|
|
|
} else if (joined) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ret->append(ProString());
|
2010-01-14 18:02:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
static inline void flushFinal(ProStringList *ret,
|
|
|
|
|
const QString ¤t, const QChar *ptr, const ProString &pending,
|
|
|
|
|
const ProString &str, bool replaced, bool joined)
|
2010-01-14 18:02:22 +01:00
|
|
|
{
|
|
|
|
|
int len = ptr - current.data();
|
|
|
|
|
if (len) {
|
|
|
|
|
if (!replaced && len == str.size())
|
|
|
|
|
ret->append(str);
|
|
|
|
|
else
|
2010-04-27 18:39:10 +02:00
|
|
|
ret->append(ProString(QString(current.data(), len), NoHash));
|
2010-01-14 18:02:22 +01:00
|
|
|
} else if (!pending.isEmpty()) {
|
|
|
|
|
ret->append(pending);
|
2010-04-27 22:00:11 +02:00
|
|
|
} else if (joined) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ret->append(ProString());
|
2010-01-14 18:02:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ProFileEvaluator::Private::expandVariableReferences(
|
|
|
|
|
const ProString &str, int *pos, bool joined)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ret;
|
2009-03-11 17:47:43 +01:00
|
|
|
// if (ok)
|
|
|
|
|
// *ok = true;
|
2010-04-28 14:32:46 +02:00
|
|
|
if (str.isEmpty() && !pos)
|
2008-12-02 12:01:29 +01:00
|
|
|
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-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-04-27 18:39:10 +02:00
|
|
|
const ushort *str_data = (const ushort *)str.constData();
|
|
|
|
|
const int str_len = str.size();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString var, args;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-14 18:02:22 +01:00
|
|
|
bool replaced = false;
|
2010-04-27 22:00:11 +02:00
|
|
|
bool putSpace = false;
|
2010-01-14 18:02:22 +01:00
|
|
|
QString current; // Buffer for successively assembled string segments
|
|
|
|
|
current.resize(str.size());
|
|
|
|
|
QChar *ptr = current.data();
|
2010-04-27 18:39:10 +02:00
|
|
|
ProString pending; // Buffer for string segments from variables
|
2010-01-14 18:02:22 +01:00
|
|
|
// 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-04-27 18:39:10 +02:00
|
|
|
var = str.mid(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-04-27 18:39:10 +02:00
|
|
|
args = str.mid(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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Missing %1 terminator [found %2]")
|
|
|
|
|
.arg(QChar(term))
|
|
|
|
|
.arg(unicode ? QString(unicode) : fL1S("end-of-line")));
|
2009-03-11 17:47:43 +01:00
|
|
|
// if (ok)
|
|
|
|
|
// *ok = false;
|
2010-01-19 12:31:39 +01:00
|
|
|
if (pos)
|
|
|
|
|
*pos = str_len;
|
2010-04-27 18:39:10 +02:00
|
|
|
return ProStringList();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList replacement;
|
2008-12-02 12:01:29 +01:00
|
|
|
if (var_type == ENVIRON) {
|
2010-04-27 18:39:10 +02:00
|
|
|
replacement = split_value_list(QString::fromLocal8Bit(qgetenv(
|
2010-06-10 15:00:16 +02:00
|
|
|
var.toQString(m_tmp1).toLocal8Bit().constData())));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (var_type == PROPERTY) {
|
2010-04-27 18:39:10 +02:00
|
|
|
replacement << ProString(propertyValue(var.toQString(m_tmp1)), NoHash);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (var_type == FUNCTION) {
|
2010-04-27 18:39:10 +02:00
|
|
|
replacement += evaluateExpandFunction(var, args);
|
2008-12-02 12:01:29 +01:00
|
|
|
} 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()) {
|
2010-04-27 22:00:11 +02:00
|
|
|
if (quote || joined) {
|
|
|
|
|
if (putSpace) {
|
|
|
|
|
putSpace = false;
|
|
|
|
|
if (!replacement.at(0).isEmpty()) // Bizarre, indeed
|
|
|
|
|
appendChar(' ', ¤t, &ptr, &pending);
|
|
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
appendString(ProString(replacement.join(statics.field_sep), NoHash),
|
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) {
|
2010-04-27 22:00:11 +02:00
|
|
|
flushCurrent(&ret, ¤t, &ptr, &pending, false);
|
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;
|
2010-04-01 16:33:48 +02:00
|
|
|
} else if (unicode == SPACE || unicode == TAB) {
|
2010-04-27 22:00:11 +02:00
|
|
|
if (!joined)
|
|
|
|
|
flushCurrent(&ret, ¤t, &ptr, &pending, false);
|
|
|
|
|
else if ((ptr - (QChar*)current.constData()) || !pending.isEmpty())
|
|
|
|
|
putSpace = true;
|
2010-01-14 18:02:22 +01:00
|
|
|
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) {
|
2010-04-27 22:00:11 +02:00
|
|
|
if (!joined) {
|
|
|
|
|
*pos = i + 1;
|
|
|
|
|
flushFinal(&ret, current, ptr, pending, str, replaced, false);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
flushCurrent(&ret, ¤t, &ptr, &pending, true);
|
|
|
|
|
putSpace = false;
|
|
|
|
|
continue;
|
2010-01-19 12:31:39 +01:00
|
|
|
}
|
2009-03-11 17:47:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-04-27 22:00:11 +02:00
|
|
|
if (putSpace) {
|
|
|
|
|
putSpace = false;
|
|
|
|
|
appendChar(' ', ¤t, &ptr, &pending);
|
|
|
|
|
}
|
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-04-27 22:00:11 +02:00
|
|
|
flushFinal(&ret, current, ptr, pending, str, replaced, joined);
|
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('?')))) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QString cfg = config;
|
|
|
|
|
cfg.detach(); // Keep m_tmp out of QRegExp's cache
|
|
|
|
|
QRegExp re(cfg, Qt::CaseSensitive, QRegExp::Wildcard);
|
2009-07-02 11:05:01 +10:00
|
|
|
|
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-04-27 18:39:10 +02:00
|
|
|
int t = 0;
|
|
|
|
|
foreach (const ProString &configValue, valuesDirect(statics.strCONFIG)) {
|
|
|
|
|
if (re.exactMatch(configValue.toQString(m_tmp[t])))
|
2009-07-02 11:05:01 +10:00
|
|
|
return true;
|
2010-04-27 18:39:10 +02:00
|
|
|
t ^= 1;
|
2009-07-02 11:05:01 +10:00
|
|
|
}
|
|
|
|
|
} 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-04-27 18:39:10 +02:00
|
|
|
if (valuesDirect(statics.strCONFIG).contains(ProString(config, NoHash)))
|
2010-04-29 17:03:39 +02:00
|
|
|
return true;
|
2009-07-02 11:05:01 +10:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
ProStringList ProFileEvaluator::Private::expandVariableReferences(
|
2010-05-31 21:07:14 +02:00
|
|
|
const ushort *&tokPtr, int sizeHint, bool joined)
|
2010-06-01 18:43:11 +02:00
|
|
|
{
|
|
|
|
|
ProStringList ret;
|
2010-05-31 21:07:14 +02:00
|
|
|
ret.reserve(sizeHint);
|
2010-06-01 18:43:11 +02:00
|
|
|
forever {
|
|
|
|
|
evaluateExpression(tokPtr, &ret, joined);
|
|
|
|
|
switch (*tokPtr) {
|
|
|
|
|
case TokValueTerminator:
|
|
|
|
|
case TokFuncTerminator:
|
|
|
|
|
tokPtr++;
|
|
|
|
|
return ret;
|
|
|
|
|
case TokArgSeparator:
|
|
|
|
|
if (joined) {
|
|
|
|
|
tokPtr++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// fallthrough
|
|
|
|
|
default:
|
|
|
|
|
Q_ASSERT_X(false, "expandVariableReferences", "Unrecognized token");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<ProStringList> ProFileEvaluator::Private::prepareFunctionArgs(const ushort *&tokPtr)
|
|
|
|
|
{
|
|
|
|
|
QList<ProStringList> args_list;
|
|
|
|
|
if (*tokPtr != TokFuncTerminator) {
|
|
|
|
|
for (;; tokPtr++) {
|
|
|
|
|
ProStringList arg;
|
|
|
|
|
evaluateExpression(tokPtr, &arg, false);
|
|
|
|
|
args_list << arg;
|
|
|
|
|
if (*tokPtr == TokFuncTerminator)
|
|
|
|
|
break;
|
|
|
|
|
Q_ASSERT(*tokPtr == TokArgSeparator);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tokPtr++;
|
|
|
|
|
return args_list;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
QList<ProStringList> ProFileEvaluator::Private::prepareFunctionArgs(const ProString &arguments)
|
2009-08-14 17:36:07 +02:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
QList<ProStringList> args_list;
|
|
|
|
|
for (int pos = 0; pos < arguments.size(); )
|
2010-04-01 16:33:48 +02:00
|
|
|
args_list << expandVariableReferences(arguments, &pos);
|
2009-08-14 17:36:07 +02:00
|
|
|
return args_list;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ProFileEvaluator::Private::evaluateFunction(
|
2010-05-11 12:24:05 +02:00
|
|
|
const FunctionDef &func, const QList<ProStringList> &argumentsList, bool *ok)
|
2009-05-18 17:46:30 +02:00
|
|
|
{
|
|
|
|
|
bool oki;
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ret;
|
2009-05-18 17:46:30 +02:00
|
|
|
|
|
|
|
|
if (m_valuemapStack.count() >= 100) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("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 {
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.push(QHash<ProString, ProStringList>());
|
2010-06-23 13:58:44 +02:00
|
|
|
m_locationStack.push(m_current);
|
2010-04-19 22:35:58 +02:00
|
|
|
int loopLevel = m_loopLevel;
|
|
|
|
|
m_loopLevel = 0;
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList args;
|
2009-05-18 17:46:30 +02:00
|
|
|
for (int i = 0; i < argumentsList.count(); ++i) {
|
2009-08-14 17:36:07 +02:00
|
|
|
args += argumentsList[i];
|
2010-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack.top()[ProString(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-06-23 13:58:44 +02:00
|
|
|
oki = (visitProBlock(func.pro(), func.tokPtr()) != ReturnFalse); // True || Return
|
2009-05-18 17:46:30 +02:00
|
|
|
ret = m_returnValue;
|
|
|
|
|
m_returnValue.clear();
|
|
|
|
|
|
2010-04-19 22:35:58 +02:00
|
|
|
m_loopLevel = loopLevel;
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current = m_locationStack.pop();
|
2010-02-09 20:38:21 +01:00
|
|
|
m_valuemapStack.pop();
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
|
|
|
|
if (ok)
|
|
|
|
|
*ok = oki;
|
|
|
|
|
if (oki)
|
|
|
|
|
return ret;
|
2010-04-27 18:39:10 +02:00
|
|
|
return ProStringList();
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-21 21:18:17 +02:00
|
|
|
ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateBoolFunction(
|
|
|
|
|
const FunctionDef &func, const QList<ProStringList> &argumentsList,
|
|
|
|
|
const ProString &function)
|
|
|
|
|
{
|
|
|
|
|
bool ok;
|
|
|
|
|
ProStringList ret = evaluateFunction(func, argumentsList, &ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
if (ret.isEmpty())
|
|
|
|
|
return ReturnTrue;
|
|
|
|
|
if (ret.at(0) != statics.strfalse) {
|
|
|
|
|
if (ret.at(0) == statics.strtrue)
|
|
|
|
|
return ReturnTrue;
|
|
|
|
|
int val = ret.at(0).toQString(m_tmp1).toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
if (val)
|
|
|
|
|
return ReturnTrue;
|
|
|
|
|
} else {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Unexpected return value from test '%1': %2")
|
|
|
|
|
.arg(function.toQString(m_tmp1))
|
|
|
|
|
.arg(ret.join(QLatin1String(" :: "))));
|
2010-05-21 21:18:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ReturnFalse;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
ProStringList ProFileEvaluator::Private::evaluateExpandFunction(
|
|
|
|
|
const ProString &func, const ushort *&tokPtr)
|
|
|
|
|
{
|
|
|
|
|
QHash<ProString, FunctionDef>::ConstIterator it =
|
|
|
|
|
m_functionDefs.replaceFunctions.constFind(func);
|
|
|
|
|
if (it != m_functionDefs.replaceFunctions.constEnd())
|
|
|
|
|
return evaluateFunction(*it, prepareFunctionArgs(tokPtr), 0);
|
|
|
|
|
|
|
|
|
|
//why don't the builtin functions just use args_list? --Sam
|
2010-05-31 21:07:14 +02:00
|
|
|
return evaluateExpandFunction(func, expandVariableReferences(tokPtr, 5, true));
|
2010-06-01 18:43:11 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ProFileEvaluator::Private::evaluateExpandFunction(
|
|
|
|
|
const ProString &func, const ProString &arguments)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-05-11 12:24:05 +02:00
|
|
|
QHash<ProString, FunctionDef>::ConstIterator it =
|
|
|
|
|
m_functionDefs.replaceFunctions.constFind(func);
|
|
|
|
|
if (it != m_functionDefs.replaceFunctions.constEnd())
|
|
|
|
|
return evaluateFunction(*it, prepareFunctionArgs(arguments), 0);
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2010-04-27 22:00:11 +02:00
|
|
|
//why don't the builtin functions just use args_list? --Sam
|
|
|
|
|
int pos = 0;
|
2010-06-01 18:43:11 +02:00
|
|
|
return evaluateExpandFunction(func, expandVariableReferences(arguments, &pos, true));
|
|
|
|
|
}
|
2010-02-08 16:47:25 +01:00
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
ProStringList ProFileEvaluator::Private::evaluateExpandFunction(
|
|
|
|
|
const ProString &func, const ProStringList &args)
|
|
|
|
|
{
|
2010-06-24 13:44:28 +02:00
|
|
|
ExpandFunc func_t = ExpandFunc(statics.expands.value(func));
|
|
|
|
|
if (func_t == 0) {
|
|
|
|
|
const QString &fn = func.toQString(m_tmp1);
|
|
|
|
|
const QString &lfn = fn.toLower();
|
|
|
|
|
if (!fn.isSharedWith(lfn))
|
|
|
|
|
func_t = ExpandFunc(statics.expands.value(ProString(lfn)));
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ret;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
switch (func_t) {
|
|
|
|
|
case E_BASENAME:
|
|
|
|
|
case E_DIRNAME:
|
|
|
|
|
case E_SECTION: {
|
|
|
|
|
bool regexp = false;
|
2010-04-27 18:39:10 +02:00
|
|
|
QString sep;
|
|
|
|
|
ProString var;
|
2008-12-02 12:01:29 +01:00
|
|
|
int beg = 0;
|
|
|
|
|
int end = -1;
|
|
|
|
|
if (func_t == E_SECTION) {
|
|
|
|
|
if (args.count() != 3 && args.count() != 4) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("%1(var) section(var, sep, begin, end) requires"
|
|
|
|
|
" three or four arguments.").arg(func.toQString(m_tmp1)));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
|
var = args[0];
|
2010-04-27 18:39:10 +02:00
|
|
|
sep = args.at(1).toQString();
|
|
|
|
|
beg = args.at(2).toQString(m_tmp2).toInt();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() == 4)
|
2010-04-27 18:39:10 +02:00
|
|
|
end = args.at(3).toQString(m_tmp2).toInt();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (args.count() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("%1(var) requires one argument.").arg(func.toQString(m_tmp1)));
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
if (!var.isEmpty()) {
|
2010-01-19 18:36:03 +01:00
|
|
|
if (regexp) {
|
|
|
|
|
QRegExp sepRx(sep);
|
2010-04-27 18:39:10 +02:00
|
|
|
foreach (const ProString &str, values(map(var))) {
|
|
|
|
|
const QString &rstr = str.toQString(m_tmp1).section(sepRx, beg, end);
|
|
|
|
|
ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr, NoHash));
|
|
|
|
|
}
|
2010-01-19 18:36:03 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
foreach (const ProString &str, values(map(var))) {
|
|
|
|
|
const QString &rstr = str.toQString(m_tmp1).section(sep, beg, end);
|
|
|
|
|
ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr, NoHash));
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
case E_SPRINTF:
|
|
|
|
|
if(args.count() < 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("sprintf(format, ...) requires at least one argument"));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
QString tmp = args.at(0).toQString(m_tmp1);
|
2008-12-12 16:30:31 +01:00
|
|
|
for (int i = 1; i < args.count(); ++i)
|
2010-04-27 18:39:10 +02:00
|
|
|
tmp = tmp.arg(args.at(i).toQString(m_tmp2));
|
|
|
|
|
// Note: this depends on split_value_list() making a deep copy
|
2008-12-12 16:30:31 +01:00
|
|
|
ret = split_value_list(tmp);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
case E_JOIN: {
|
|
|
|
|
if (args.count() < 1 || args.count() > 4) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("join(var, glue, before, after) requires one to four arguments."));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
QString glue;
|
|
|
|
|
ProString before, after;
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() >= 2)
|
2010-04-27 18:39:10 +02:00
|
|
|
glue = args.at(1).toQString(m_tmp1);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() >= 3)
|
|
|
|
|
before = args[2];
|
|
|
|
|
if (args.count() == 4)
|
|
|
|
|
after = args[3];
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProStringList &var = values(map(args.at(0)));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!var.isEmpty())
|
2010-04-27 18:39:10 +02:00
|
|
|
ret.append(ProString(before + var.join(glue) + after, NoHash));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-08-12 13:42:29 +02:00
|
|
|
case E_SPLIT:
|
2008-12-04 19:16:48 +01:00
|
|
|
if (args.count() != 2) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("split(var, sep) requires one or two arguments"));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &sep = (args.count() == 2) ? args.at(1).toQString(m_tmp1) : statics.field_sep;
|
|
|
|
|
foreach (const ProString &var, values(map(args.at(0))))
|
|
|
|
|
foreach (const QString &splt, var.toQString(m_tmp2).split(sep))
|
|
|
|
|
ret << (splt.isSharedWith(m_tmp2) ? var : ProString(splt, NoHash));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("member(var, start, end) requires one to three arguments."));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
|
bool ok = true;
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProStringList &var = values(map(args.at(0)));
|
2008-12-02 12:01:29 +01:00
|
|
|
int start = 0, end = 0;
|
|
|
|
|
if (args.count() >= 2) {
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &start_str = args.at(1).toQString(m_tmp1);
|
2008-12-02 12:01:29 +01:00
|
|
|
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)
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("member() argument 2 (start) '%2' invalid.")
|
|
|
|
|
.arg(start_str));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
|
end = start;
|
|
|
|
|
if (args.count() == 3)
|
2010-04-27 18:39:10 +02:00
|
|
|
end = args.at(2).toQString(m_tmp1).toInt(&ok);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!ok)
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("member() argument 3 (end) '%2' invalid.\n")
|
|
|
|
|
.arg(args.at(2).toQString(m_tmp1)));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("%1(var) requires one argument.").arg(func.toQString(m_tmp1)));
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProStringList &var = values(map(args.at(0)));
|
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;
|
2010-04-28 11:37:51 +02:00
|
|
|
case E_SIZE:
|
|
|
|
|
if(args.count() != 1)
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("size(var) requires one argument."));
|
2010-04-28 11:37:51 +02:00
|
|
|
else
|
2010-04-27 18:39:10 +02:00
|
|
|
ret.append(ProString(QString::number(values(map(args.at(0))).size()), NoHash));
|
2010-04-28 11:37:51 +02:00
|
|
|
break;
|
2008-12-12 16:30:31 +01:00
|
|
|
case E_CAT:
|
|
|
|
|
if (args.count() < 1 || args.count() > 2) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("cat(file, singleline=true) requires one or two arguments."));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &file = args.at(0).toQString(m_tmp1);
|
2008-12-12 16:30:31 +01:00
|
|
|
|
|
|
|
|
bool singleLine = true;
|
|
|
|
|
if (args.count() > 1)
|
2010-04-27 18:39:10 +02:00
|
|
|
singleLine = isTrue(args.at(1), m_tmp2);
|
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)
|
2010-04-27 18:39:10 +02:00
|
|
|
ret += ProString("\n", NoHash);
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
qfile.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case E_FROMFILE:
|
|
|
|
|
if (args.count() != 2) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("fromfile(file, variable) requires two arguments."));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> vars;
|
2010-06-15 20:50:21 +02:00
|
|
|
QString fn = resolvePath(expandEnvVars(args.at(0).toQString(m_tmp1)));
|
|
|
|
|
fn.detach();
|
2010-06-22 12:07:27 +02:00
|
|
|
if (evaluateFileInto(fn, ProFileEvaluatorHandler::EvalAuxFile,
|
|
|
|
|
&vars, &m_functionDefs, EvalWithDefaults))
|
2010-04-27 18:39:10 +02:00
|
|
|
ret = vars.value(map(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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("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++);
|
2010-04-27 18:39:10 +02:00
|
|
|
ret = ProStringList(ProString(tmp, NoHash));
|
|
|
|
|
ProStringList lst;
|
|
|
|
|
foreach (const ProString &arg, args)
|
|
|
|
|
lst += split_value_list(arg.toQString(m_tmp1)); // Relies on deep copy
|
|
|
|
|
m_valuemapStack.top()[ret.at(0)] = lst;
|
2008-12-12 16:30:31 +01:00
|
|
|
break; }
|
|
|
|
|
case E_FIND:
|
|
|
|
|
if (args.count() != 2) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("find(var, str) requires two arguments."));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
QRegExp regx(args.at(1).toQString());
|
|
|
|
|
int t = 0;
|
|
|
|
|
foreach (const ProString &val, values(map(args.at(0)))) {
|
|
|
|
|
if (regx.indexIn(val.toQString(m_tmp[t])) != -1)
|
2008-12-12 16:30:31 +01:00
|
|
|
ret += val;
|
2010-04-27 18:39:10 +02:00
|
|
|
t ^= 1;
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("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)
|
2010-04-27 18:39:10 +02:00
|
|
|
singleLine = isTrue(args.at(1), m_tmp2);
|
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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("unique(var) requires one argument."));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
ret = values(map(args.at(0)));
|
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:
|
2010-04-29 17:58:47 +02:00
|
|
|
ret += args;
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
2008-12-12 16:30:31 +01:00
|
|
|
case E_ESCAPE_EXPAND:
|
|
|
|
|
for (int i = 0; i < args.size(); ++i) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QString str = args.at(i).toQString();
|
|
|
|
|
QChar *i_data = str.data();
|
|
|
|
|
int i_len = str.length();
|
2008-12-12 16:30:31 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
ret.append(ProString(QString(i_data, i_len), NoHash));
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case E_RE_ESCAPE:
|
2010-04-27 18:39:10 +02:00
|
|
|
for (int i = 0; i < args.size(); ++i) {
|
|
|
|
|
const QString &rstr = QRegExp::escape(args.at(i).toQString(m_tmp1));
|
|
|
|
|
ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr, NoHash));
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
break;
|
|
|
|
|
case E_UPPER:
|
|
|
|
|
case E_LOWER:
|
2010-04-27 18:39:10 +02:00
|
|
|
for (int i = 0; i < args.count(); ++i) {
|
|
|
|
|
QString rstr = args.at(i).toQString(m_tmp1);
|
|
|
|
|
rstr = (func_t == E_UPPER) ? rstr.toUpper() : rstr.toLower();
|
|
|
|
|
ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr, NoHash));
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
break;
|
|
|
|
|
case E_FILES:
|
|
|
|
|
if (args.count() != 1 && args.count() != 2) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("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-04-27 18:39:10 +02:00
|
|
|
recursive = isTrue(args.at(1), m_tmp2);
|
2008-12-12 16:30:31 +01:00
|
|
|
QStringList dirs;
|
2010-04-27 18:39:10 +02:00
|
|
|
QString r = fixPathToLocalOS(args.at(0).toQString(m_tmp1));
|
2010-02-10 13:12:01 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
r.detach(); // Keep m_tmp out of QRegExp's cache
|
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]))
|
2010-04-27 18:39:10 +02:00
|
|
|
ret += ProString(fname, NoHash);
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case E_REPLACE:
|
|
|
|
|
if(args.count() != 3 ) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("replace(var, before, after) requires three arguments"));
|
2008-12-12 16:30:31 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
const QRegExp before(args.at(1).toQString());
|
|
|
|
|
const QString &after(args.at(2).toQString(m_tmp2));
|
|
|
|
|
foreach (const ProString &val, values(map(args.at(0)))) {
|
|
|
|
|
QString rstr = val.toQString(m_tmp1);
|
|
|
|
|
QString copy = rstr; // Force a detach on modify
|
|
|
|
|
rstr.replace(before, after);
|
|
|
|
|
ret << (rstr.isSharedWith(m_tmp1) ? val : ProString(rstr, NoHash));
|
|
|
|
|
}
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
case 0:
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("'%1' is not a recognized replace function")
|
|
|
|
|
.arg(func.toQString(m_tmp1)));
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Function '%1' is not implemented").arg(func.toQString(m_tmp1)));
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-29 21:43:41 +02:00
|
|
|
ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &function, const ProString &arguments)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-05-11 12:24:05 +02:00
|
|
|
QHash<ProString, FunctionDef>::ConstIterator it =
|
|
|
|
|
m_functionDefs.testFunctions.constFind(function);
|
2010-05-21 21:18:17 +02:00
|
|
|
if (it != m_functionDefs.testFunctions.constEnd())
|
|
|
|
|
return evaluateBoolFunction(*it, prepareFunctionArgs(arguments), function);
|
2009-05-18 17:46:30 +02:00
|
|
|
|
2010-04-27 22:00:11 +02:00
|
|
|
//why don't the builtin functions just use args_list? --Sam
|
|
|
|
|
int pos = 0;
|
2010-06-01 18:43:11 +02:00
|
|
|
return evaluateConditionalFunction(function, expandVariableReferences(arguments, &pos, true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(
|
|
|
|
|
const ProString &function, const ushort *&tokPtr)
|
|
|
|
|
{
|
|
|
|
|
QHash<ProString, FunctionDef>::ConstIterator it =
|
|
|
|
|
m_functionDefs.testFunctions.constFind(function);
|
|
|
|
|
if (it != m_functionDefs.testFunctions.constEnd())
|
|
|
|
|
return evaluateBoolFunction(*it, prepareFunctionArgs(tokPtr), function);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-06-01 18:43:11 +02:00
|
|
|
//why don't the builtin functions just use args_list? --Sam
|
2010-05-31 21:07:14 +02:00
|
|
|
return evaluateConditionalFunction(function, expandVariableReferences(tokPtr, 5, true));
|
2010-06-01 18:43:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(
|
|
|
|
|
const ProString &function, const ProStringList &args)
|
|
|
|
|
{
|
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_DEFINED:
|
|
|
|
|
if (args.count() < 1 || args.count() > 2) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("defined(function, [\"test\"|\"replace\"])"
|
|
|
|
|
" requires one or two arguments."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
|
|
|
|
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]));
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("defined(function, type): unexpected type [%1].\n")
|
|
|
|
|
.arg(args.at(1).toQString(m_tmp1)));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
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)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2009-05-18 17:46:30 +02:00
|
|
|
if (m_valuemapStack.isEmpty()) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("unexpected return()."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2009-05-18 17:46:30 +02:00
|
|
|
if (args.count() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("export(variable) requires one argument."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-18 17:46:30 +02:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &var = map(args.at(0));
|
2010-02-09 20:38:21 +01:00
|
|
|
for (int i = m_valuemapStack.size(); --i > 0; ) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList>::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-04-27 18:39:10 +02:00
|
|
|
m_valuemapStack[0][var] = ProStringList();
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("infile(file, var, [values]) requires two or three arguments."));
|
2009-09-23 18:19:09 +02:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> vars;
|
2010-06-15 20:50:21 +02:00
|
|
|
QString fn = resolvePath(expandEnvVars(args.at(0).toQString(m_tmp1)));
|
|
|
|
|
fn.detach();
|
2010-06-22 12:07:27 +02:00
|
|
|
if (!evaluateFileInto(fn, ProFileEvaluatorHandler::EvalAuxFile,
|
|
|
|
|
&vars, &m_functionDefs, EvalWithDefaults))
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-09-23 18:19:09 +02:00
|
|
|
if (args.count() == 2)
|
|
|
|
|
return returnBool(vars.contains(args.at(1)));
|
2010-01-19 18:36:03 +01:00
|
|
|
QRegExp regx;
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &qry = args.at(2).toQString(m_tmp1);
|
|
|
|
|
if (qry != QRegExp::escape(qry)) {
|
|
|
|
|
QString copy = qry;
|
|
|
|
|
copy.detach();
|
|
|
|
|
regx.setPattern(copy);
|
|
|
|
|
}
|
|
|
|
|
int t = 0;
|
|
|
|
|
foreach (const ProString &s, vars.value(map(args.at(1)))) {
|
|
|
|
|
if ((!regx.isEmpty() && regx.exactMatch(s.toQString(m_tmp[t]))) || s == qry)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2010-04-27 18:39:10 +02:00
|
|
|
t ^= 1;
|
|
|
|
|
}
|
2009-09-23 18:19:09 +02:00
|
|
|
}
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-09-23 18:19:09 +02:00
|
|
|
#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-06-18 19:48:07 +02:00
|
|
|
ProFile *pro = m_parser->parsedProFile(fL1S("(eval)"), false,
|
|
|
|
|
args.join(statics.field_sep));
|
|
|
|
|
if (!pro)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2010-06-23 13:58:44 +02:00
|
|
|
m_locationStack.push(m_current);
|
2010-06-23 14:51:43 +02:00
|
|
|
VisitReturn ret = visitProBlock(pro, pro->tokPtr());
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current = m_locationStack.pop();
|
2010-06-18 19:48:07 +02:00
|
|
|
pro->deref();
|
2010-04-19 22:35:58 +02:00
|
|
|
return ret;
|
2009-05-19 19:00:06 +02:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_BREAK:
|
2009-05-19 19:00:06 +02:00
|
|
|
if (m_skipLevel)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2010-04-19 22:35:58 +02:00
|
|
|
if (m_loopLevel)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnBreak;
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("unexpected break()."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_NEXT:
|
2009-05-19 19:00:06 +02:00
|
|
|
if (m_skipLevel)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2010-04-19 22:35:58 +02:00
|
|
|
if (m_loopLevel)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnNext;
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("unexpected next()."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-18 15:42:45 +02:00
|
|
|
case T_IF: {
|
2010-04-08 15:36:17 +02:00
|
|
|
if (m_skipLevel && !m_cumulative)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-18 15:42:45 +02:00
|
|
|
if (args.count() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("if(condition) requires one argument."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-18 15:42:45 +02:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &cond = args.at(0);
|
2009-05-18 15:42:45 +02:00
|
|
|
bool quoted = false;
|
|
|
|
|
bool ret = true;
|
|
|
|
|
bool orOp = false;
|
|
|
|
|
bool invert = false;
|
|
|
|
|
bool isFunc = false;
|
|
|
|
|
int parens = 0;
|
|
|
|
|
QString test;
|
|
|
|
|
test.reserve(20);
|
2010-06-11 13:35:22 +10:00
|
|
|
QString argsString;
|
|
|
|
|
argsString.reserve(50);
|
2010-04-27 18:39:10 +02:00
|
|
|
const QChar *d = cond.constData();
|
|
|
|
|
const QChar *ed = d + cond.size();
|
2009-05-18 15:42:45 +02:00
|
|
|
while (d < ed) {
|
|
|
|
|
ushort c = (d++)->unicode();
|
2010-05-17 14:19:56 +02:00
|
|
|
bool isOp = false;
|
2009-05-18 15:42:45 +02:00
|
|
|
if (quoted) {
|
2010-05-17 14:19:56 +02:00
|
|
|
if (c == '"')
|
|
|
|
|
quoted = false;
|
|
|
|
|
else if (c == '!' && test.isEmpty())
|
|
|
|
|
invert = true;
|
|
|
|
|
else
|
|
|
|
|
test += c;
|
|
|
|
|
} else if (c == '(') {
|
|
|
|
|
isFunc = true;
|
|
|
|
|
if (parens)
|
2010-06-11 13:35:22 +10:00
|
|
|
argsString += c;
|
2010-05-17 14:19:56 +02:00
|
|
|
++parens;
|
|
|
|
|
} else if (c == ')') {
|
|
|
|
|
--parens;
|
|
|
|
|
if (parens)
|
2010-06-11 13:35:22 +10:00
|
|
|
argsString += c;
|
2010-05-17 14:19:56 +02:00
|
|
|
} else if (!parens) {
|
|
|
|
|
if (c == '"')
|
|
|
|
|
quoted = true;
|
|
|
|
|
else if (c == ':' || c == '|')
|
|
|
|
|
isOp = true;
|
|
|
|
|
else if (c == '!' && test.isEmpty())
|
|
|
|
|
invert = true;
|
|
|
|
|
else
|
|
|
|
|
test += c;
|
2009-05-18 15:42:45 +02:00
|
|
|
} else {
|
2010-06-11 13:35:22 +10:00
|
|
|
argsString += c;
|
2010-05-17 14:19:56 +02:00
|
|
|
}
|
|
|
|
|
if (!quoted && !parens && (isOp || d == ed)) {
|
|
|
|
|
if (m_cumulative || (orOp != ret)) {
|
|
|
|
|
if (isFunc)
|
2010-06-11 13:35:22 +10:00
|
|
|
ret = evaluateConditionalFunction(ProString(test), ProString(argsString, NoHash));
|
2009-05-18 15:42:45 +02:00
|
|
|
else
|
2010-05-17 14:19:56 +02:00
|
|
|
ret = isActiveConfig(test, true);
|
|
|
|
|
ret ^= invert;
|
2009-05-18 15:42:45 +02:00
|
|
|
}
|
2010-05-17 14:19:56 +02:00
|
|
|
orOp = (c == '|');
|
|
|
|
|
invert = false;
|
|
|
|
|
isFunc = false;
|
|
|
|
|
test.clear();
|
2010-06-11 13:35:22 +10:00
|
|
|
argsString.clear();
|
2009-05-18 15:42:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("CONFIG(config) requires one or two arguments."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-02-10 13:20:16 +01:00
|
|
|
if (args.count() == 1)
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool(isActiveConfig(args.at(0).toQString(m_tmp2)));
|
|
|
|
|
const QStringList &mutuals = args.at(1).toQString(m_tmp2).split(QLatin1Char('|'));
|
|
|
|
|
const ProStringList &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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("contains(var, val) requires two or three arguments."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &qry = args.at(1).toQString(m_tmp1);
|
2010-01-19 18:36:03 +01:00
|
|
|
QRegExp regx;
|
2010-04-27 18:39:10 +02:00
|
|
|
if (qry != QRegExp::escape(qry)) {
|
|
|
|
|
QString copy = qry;
|
|
|
|
|
copy.detach();
|
|
|
|
|
regx.setPattern(copy);
|
|
|
|
|
}
|
|
|
|
|
const ProStringList &l = values(map(args.at(0)));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() == 2) {
|
2010-04-27 18:39:10 +02:00
|
|
|
int t = 0;
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int i = 0; i < l.size(); ++i) {
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &val = l[i];
|
|
|
|
|
if ((!regx.isEmpty() && regx.exactMatch(val.toQString(m_tmp[t]))) || val == qry)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2010-04-27 18:39:10 +02:00
|
|
|
t ^= 1;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
const QStringList &mutuals = args.at(2).toQString(m_tmp3).split(QLatin1Char('|'));
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int i = l.size() - 1; i >= 0; i--) {
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString val = l[i];
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int mut = 0; mut < mutuals.count(); mut++) {
|
|
|
|
|
if (val == mutuals[mut].trimmed()) {
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool((!regx.isEmpty()
|
|
|
|
|
&& regx.exactMatch(val.toQString(m_tmp2)))
|
2010-01-19 18:36:03 +01:00
|
|
|
|| val == qry);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("count(var, count, op=\"equals\") requires two or three arguments."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
int cnt = values(map(args.at(0))).count();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() == 3) {
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &comp = args.at(2);
|
|
|
|
|
const int val = args.at(1).toQString(m_tmp1).toInt();
|
2008-12-02 12:01:29 +01:00
|
|
|
if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool(cnt > val);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (comp == QLatin1String(">=")) {
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool(cnt >= val);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) {
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool(cnt < val);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (comp == QLatin1String("<=")) {
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool(cnt <= val);
|
2009-05-12 17:15:54 +02:00
|
|
|
} else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual")
|
|
|
|
|
|| comp == QLatin1String("=") || comp == QLatin1String("==")) {
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool(cnt == val);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("unexpected modifier to count(%2)").arg(comp.toQString(m_tmp1)));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool(cnt == args.at(1).toQString(m_tmp1).toInt());
|
2010-02-11 15:53:35 +01:00
|
|
|
}
|
2009-05-14 17:14:37 +02:00
|
|
|
case T_GREATERTHAN:
|
|
|
|
|
case T_LESSTHAN: {
|
|
|
|
|
if (args.count() != 2) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("%1(variable, value) requires two arguments.")
|
|
|
|
|
.arg(function.toQString(m_tmp1)));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-14 17:14:37 +02:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &rhs(args.at(1).toQString(m_tmp1)),
|
|
|
|
|
&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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("%1(variable, value) requires two arguments.")
|
|
|
|
|
.arg(function.toQString(m_tmp1)));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-14 17:14:37 +02:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool(values(map(args.at(0))).join(statics.field_sep)
|
|
|
|
|
== args.at(1).toQString(m_tmp1));
|
2009-05-14 17:14:37 +02:00
|
|
|
case T_CLEAR: {
|
|
|
|
|
if (m_skipLevel && !m_cumulative)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-14 17:14:37 +02:00
|
|
|
if (args.count() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("%1(variable) requires one argument.")
|
|
|
|
|
.arg(function.toQString(m_tmp1)));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-14 17:14:37 +02:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> *hsh;
|
|
|
|
|
QHash<ProString, ProStringList>::Iterator it;
|
|
|
|
|
const ProString &var = map(args.at(0));
|
2010-02-11 16:33:16 +01:00
|
|
|
if (!(hsh = findValues(var, &it)))
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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();
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2009-05-14 17:14:37 +02:00
|
|
|
}
|
|
|
|
|
case T_UNSET: {
|
|
|
|
|
if (m_skipLevel && !m_cumulative)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-14 17:14:37 +02:00
|
|
|
if (args.count() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("%1(variable) requires one argument.")
|
|
|
|
|
.arg(function.toQString(m_tmp1)));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2009-05-14 17:14:37 +02:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> *hsh;
|
|
|
|
|
QHash<ProString, ProStringList>::Iterator it;
|
|
|
|
|
const ProString &var = map(args.at(0));
|
2010-02-11 16:33:16 +01:00
|
|
|
if (!(hsh = findValues(var, &it)))
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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;
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2009-05-14 17:14:37 +02:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_INCLUDE: {
|
2008-12-17 18:52:14 +01:00
|
|
|
if (m_skipLevel && !m_cumulative)
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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) ) {
|
2010-04-27 18:39:10 +02:00
|
|
|
parseInto = args.at(1).toQString(m_tmp2);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (args.count() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("include(file, into, silent) requires one, two or three arguments."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-06-15 20:50:57 +02:00
|
|
|
QString fn = resolvePath(expandEnvVars(args.at(0).toQString(m_tmp1)));
|
|
|
|
|
fn.detach();
|
2010-02-11 14:13:59 +01:00
|
|
|
bool ok;
|
|
|
|
|
if (parseInto.isEmpty()) {
|
2010-06-18 13:30:03 +02:00
|
|
|
ok = evaluateFile(fn, ProFileEvaluatorHandler::EvalIncludeFile);
|
2010-02-11 14:13:59 +01:00
|
|
|
} else {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> symbols;
|
2010-06-22 12:07:27 +02:00
|
|
|
if ((ok = evaluateFileInto(fn, ProFileEvaluatorHandler::EvalAuxFile,
|
|
|
|
|
&symbols, 0, EvalWithSetup))) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> newMap;
|
|
|
|
|
for (QHash<ProString, ProStringList>::ConstIterator
|
2010-02-15 17:12:32 +01:00
|
|
|
it = m_valuemapStack.top().constBegin(),
|
|
|
|
|
end = m_valuemapStack.top().constEnd();
|
2010-04-27 18:39:10 +02:00
|
|
|
it != end; ++it) {
|
|
|
|
|
const QString &ky = it.key().toQString(m_tmp1);
|
|
|
|
|
if (!(ky.startsWith(parseInto) &&
|
|
|
|
|
(ky.length() == parseInto.length()
|
|
|
|
|
|| ky.at(parseInto.length()) == QLatin1Char('.'))))
|
2010-02-15 17:12:32 +01:00
|
|
|
newMap[it.key()] = it.value();
|
2010-04-27 18:39:10 +02:00
|
|
|
}
|
|
|
|
|
for (QHash<ProString, ProStringList>::ConstIterator it = symbols.constBegin();
|
|
|
|
|
it != symbols.constEnd(); ++it) {
|
|
|
|
|
const QString &ky = it.key().toQString(m_tmp1);
|
|
|
|
|
if (!ky.startsWith(QLatin1Char('.')))
|
|
|
|
|
newMap.insert(ProString(parseInto + QLatin1Char('.') + ky), it.value());
|
|
|
|
|
}
|
2010-02-15 17:12:32 +01:00
|
|
|
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)
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
bool ignore_error = false;
|
|
|
|
|
if (args.count() == 2) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ignore_error = isTrue(args.at(1), m_tmp2);
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (args.count() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("load(feature) requires one or two arguments."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-05-12 17:15:54 +02:00
|
|
|
// XXX ignore_error unused
|
2010-04-27 18:39:10 +02:00
|
|
|
return returnBool(evaluateFeatureFile(expandEnvVars(args.at(0).toQString())));
|
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.
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-17 18:47:12 +01:00
|
|
|
case T_MESSAGE: {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (args.count() != 1) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("%1(message) requires one argument.")
|
|
|
|
|
.arg(function.toQString(m_tmp1)));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &msg = expandEnvVars(args.at(0).toQString(m_tmp2));
|
2010-06-18 13:30:03 +02:00
|
|
|
if (!m_skipLevel)
|
|
|
|
|
m_handler->fileMessage(fL1S("Project %1: %2")
|
|
|
|
|
.arg(function.toQString(m_tmp1).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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("system(exec) requires one argument."));
|
2010-04-29 21:43:41 +02:00
|
|
|
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())
|
2010-06-10 15:00:16 +02:00
|
|
|
+ QLatin1String(" && ") + args.at(0)).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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("isEmpty(var) requires one argument."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProStringList &sl = values(map(args.at(0)));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (sl.count() == 0) {
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
} else if (sl.count() > 0) {
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProString &var = sl.first();
|
2009-05-12 17:15:54 +02:00
|
|
|
if (var.isEmpty())
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("exists(file) requires one argument."));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
const QString &file = resolvePath(expandEnvVars(args.at(0).toQString(m_tmp1)));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(file)) {
|
2010-04-29 21:43:41 +02:00
|
|
|
return 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())
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnTrue;
|
2010-02-11 12:41:16 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-17 18:47:12 +01:00
|
|
|
case 0:
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("'%1' is not a recognized test function")
|
|
|
|
|
.arg(function.toQString(m_tmp1)));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-17 18:47:12 +01:00
|
|
|
default:
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("Function '%1' is not implemented").arg(function.toQString(m_tmp1)));
|
2010-04-29 21:43:41 +02:00
|
|
|
return ReturnFalse;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList> *ProFileEvaluator::Private::findValues(
|
|
|
|
|
const ProString &variableName, QHash<ProString, ProStringList>::Iterator *rit)
|
2010-02-09 20:38:21 +01:00
|
|
|
{
|
|
|
|
|
for (int i = m_valuemapStack.size(); --i >= 0; ) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList>::Iterator it = m_valuemapStack[i].find(variableName);
|
2010-02-09 20:38:21 +01:00
|
|
|
if (it != m_valuemapStack[i].end()) {
|
|
|
|
|
if (it->constBegin() == statics.fakeValue.constBegin())
|
|
|
|
|
return 0;
|
|
|
|
|
*rit = it;
|
|
|
|
|
return &m_valuemapStack[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList &ProFileEvaluator::Private::valuesRef(const ProString &variableName)
|
2010-02-09 20:38:21 +01:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList>::Iterator it = m_valuemapStack.top().find(variableName);
|
2010-02-09 20:38:21 +01:00
|
|
|
if (it != m_valuemapStack.top().end())
|
|
|
|
|
return *it;
|
|
|
|
|
for (int i = m_valuemapStack.size() - 1; --i >= 0; ) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
|
2010-02-09 20:38:21 +01:00
|
|
|
if (it != m_valuemapStack.at(i).constEnd()) {
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList &ret = m_valuemapStack.top()[variableName];
|
2010-02-09 20:38:21 +01:00
|
|
|
ret = *it;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return m_valuemapStack.top()[variableName];
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ProFileEvaluator::Private::valuesDirect(const ProString &variableName) const
|
2010-02-09 20:38:21 +01:00
|
|
|
{
|
|
|
|
|
for (int i = m_valuemapStack.size(); --i >= 0; ) {
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, ProStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
|
2010-02-09 20:38:21 +01:00
|
|
|
if (it != m_valuemapStack.at(i).constEnd()) {
|
|
|
|
|
if (it->constBegin() == statics.fakeValue.constBegin())
|
|
|
|
|
break;
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
return ProStringList();
|
2010-02-09 20:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList ProFileEvaluator::Private::values(const ProString &variableName) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
QHash<ProString, int>::ConstIterator vli = statics.varList.find(variableName);
|
2010-02-08 16:47:25 +01:00
|
|
|
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;
|
2010-06-23 13:58:44 +02:00
|
|
|
case V_OUT_PWD: // the outgoing dir (shadow of _PRO_FILE_PWD_)
|
2010-02-02 19:01:23 +01:00
|
|
|
ret = m_outputDir;
|
|
|
|
|
break;
|
2010-06-23 13:58:44 +02:00
|
|
|
case V_PWD: // containing directory of most nested project/include file
|
2010-02-02 19:01:23 +01:00
|
|
|
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;
|
2010-06-23 13:58:44 +02:00
|
|
|
case V__LINE_: // currently executed line number
|
|
|
|
|
ret = QString::number(m_current.line);
|
2010-02-02 19:01:23 +01:00
|
|
|
break;
|
2010-06-23 13:58:44 +02:00
|
|
|
case V__FILE_: // currently executed file
|
|
|
|
|
ret = m_current.pro->fileName();
|
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
|
|
|
}
|
2010-04-27 18:39:10 +02:00
|
|
|
return ProStringList(ProString(ret, NoHash));
|
2008-12-12 16:30:31 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-27 18:39:10 +02:00
|
|
|
ProStringList 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) {
|
2010-04-27 18:39:10 +02:00
|
|
|
result.append(ProString("app", NoHash));
|
2010-02-08 17:15:44 +01:00
|
|
|
} else if (variableName == statics.strQMAKE_DIR_SEP) {
|
2010-04-27 18:39:10 +02:00
|
|
|
result.append(ProString(m_option->dirlist_sep, NoHash));
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-07 21:25:11 +02:00
|
|
|
bool ProFileEvaluator::Private::evaluateFileDirect(
|
2010-06-18 13:30:03 +02:00
|
|
|
const QString &fileName, ProFileEvaluatorHandler::EvalFileType type)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-06-18 19:48:07 +02:00
|
|
|
if (ProFile *pro = m_parser->parsedProFile(fileName, true)) {
|
2010-06-23 13:58:44 +02:00
|
|
|
m_locationStack.push(m_current);
|
2010-06-18 20:39:45 +02:00
|
|
|
bool ok = (visitProFile(pro, type) == ReturnTrue);
|
2010-06-23 13:58:44 +02:00
|
|
|
m_current = m_locationStack.pop();
|
2009-12-07 22:58:47 +01:00
|
|
|
pro->deref();
|
2009-05-12 17:15:54 +02:00
|
|
|
return ok;
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2009-05-12 17:15:54 +02:00
|
|
|
return false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-17 12:54:32 +02:00
|
|
|
bool ProFileEvaluator::Private::evaluateFile(
|
2010-06-18 13:30:03 +02:00
|
|
|
const QString &fileName, ProFileEvaluatorHandler::EvalFileType type)
|
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) {
|
2010-06-18 13:30:03 +02:00
|
|
|
evalError(fL1S("circular inclusion of %1").arg(fileName));
|
2009-08-04 20:39:28 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2010-06-17 12:54:32 +02:00
|
|
|
return evaluateFileDirect(fileName, type);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName)
|
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-04-27 18:39:10 +02:00
|
|
|
ProStringList &already = valuesRef(ProString("QMAKE_INTERNAL_INCLUDED_FEATURES"));
|
|
|
|
|
ProString afn(fn, NoHash);
|
|
|
|
|
if (already.contains(afn))
|
2009-08-04 16:16:27 +02:00
|
|
|
return true;
|
2010-04-27 18:39:10 +02:00
|
|
|
already.append(afn);
|
2009-08-04 16:16:27 +02:00
|
|
|
} else {
|
2010-01-22 12:26:14 +01:00
|
|
|
fn = resolvePath(fn);
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
bool cumulative = m_cumulative;
|
|
|
|
|
m_cumulative = false;
|
2009-08-04 20:48:22 +02:00
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
// The path is fully normalized already.
|
|
|
|
|
bool ok = evaluateFileDirect(fn, ProFileEvaluatorHandler::EvalFeatureFile);
|
2009-08-04 20:48:22 +02:00
|
|
|
|
2010-06-22 12:02:53 +02:00
|
|
|
m_cumulative = cumulative;
|
|
|
|
|
return ok;
|
2009-08-04 16:16:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProFileEvaluator::Private::evaluateFileInto(
|
2010-06-18 13:30:03 +02:00
|
|
|
const QString &fileName, ProFileEvaluatorHandler::EvalFileType type,
|
2010-06-22 12:07:27 +02:00
|
|
|
QHash<ProString, ProStringList> *values, FunctionDefs *funcs, EvalIntoMode mode)
|
2009-08-04 16:16:27 +02:00
|
|
|
{
|
2010-06-18 19:48:07 +02:00
|
|
|
ProFileEvaluator visitor(m_option, m_parser, m_handler);
|
2009-08-04 16:16:27 +02:00
|
|
|
visitor.d->m_cumulative = false;
|
2010-06-22 12:07:27 +02:00
|
|
|
visitor.d->m_parsePreAndPostFiles = (mode == EvalWithSetup);
|
|
|
|
|
// visitor.d->m_valuemapStack.top() = *values;
|
2009-08-10 17:27:07 +02:00
|
|
|
if (funcs)
|
|
|
|
|
visitor.d->m_functionDefs = *funcs;
|
2010-06-22 12:07:27 +02:00
|
|
|
if (mode == EvalWithDefaults)
|
|
|
|
|
visitor.d->evaluateFeatureFile(QLatin1String("default_pre.prf"));
|
2010-06-17 12:54:32 +02:00
|
|
|
if (!visitor.d->evaluateFile(fileName, type))
|
2009-08-04 16:16:27 +02:00
|
|
|
return false;
|
2010-02-09 20:38:21 +01:00
|
|
|
*values = visitor.d->m_valuemapStack.top();
|
2010-06-22 12:07:27 +02:00
|
|
|
// if (funcs)
|
|
|
|
|
// *funcs = visitor.d->m_functionDefs;
|
2009-08-04 16:16:27 +02:00
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-18 13:30:03 +02:00
|
|
|
void ProFileEvaluator::Private::evalError(const QString &message) const
|
2009-08-12 13:00:21 +02:00
|
|
|
{
|
|
|
|
|
if (!m_skipLevel)
|
2010-06-23 13:58:44 +02:00
|
|
|
m_handler->evalError(m_current.pro->fileName(), m_current.line, message);
|
2009-08-12 13:00:21 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// ProFileEvaluator
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-02-08 16:47:25 +01:00
|
|
|
void ProFileEvaluator::initialize()
|
|
|
|
|
{
|
|
|
|
|
Private::initStatics();
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-18 19:48:07 +02:00
|
|
|
ProFileEvaluator::ProFileEvaluator(ProFileOption *option, ProFileParser *parser,
|
2010-06-18 13:30:03 +02:00
|
|
|
ProFileEvaluatorHandler *handler)
|
2010-06-18 19:48:07 +02:00
|
|
|
: d(new Private(this, option, parser, handler))
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProFileEvaluator::~ProFileEvaluator()
|
|
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProFileEvaluator::contains(const QString &variableName) const
|
|
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
return d->m_valuemapStack.top().contains(ProString(variableName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QStringList expandEnvVars(const ProStringList &x)
|
|
|
|
|
{
|
|
|
|
|
QStringList ret;
|
|
|
|
|
foreach (const ProString &str, x)
|
|
|
|
|
ret << expandEnvVars(str.toQString());
|
|
|
|
|
return ret;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-15 22:51:37 +02:00
|
|
|
QString ProFileEvaluator::value(const QString &variable) const
|
|
|
|
|
{
|
|
|
|
|
const QStringList &vals = values(variable);
|
|
|
|
|
if (!vals.isEmpty())
|
|
|
|
|
return vals.first();
|
|
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList ProFileEvaluator::values(const QString &variableName) const
|
|
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
return expandEnvVars(d->values(ProString(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
|
2010-04-27 18:39:10 +02:00
|
|
|
return expandEnvVars(d->m_filevaluemap.value(pro).value(ProString(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('/'));
|
2010-06-10 17:14:54 +02:00
|
|
|
QString absDir = d->m_tmp1.setRawData(absEl.constData(), nameOff);
|
2010-01-22 12:26:14 +01:00
|
|
|
if (IoUtils::exists(absDir)) {
|
2010-06-10 17:14:54 +02:00
|
|
|
QString wildcard = d->m_tmp2.setRawData(absEl.constData() + nameOff + 1,
|
2010-01-22 12:26:14 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-15 20:50:57 +02:00
|
|
|
ProFileEvaluator::TemplateType ProFileEvaluator::templateType() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-04-27 18:39:10 +02:00
|
|
|
const ProStringList &templ = d->values(statics.strTEMPLATE);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (templ.count() >= 1) {
|
2010-06-24 15:17:28 +02:00
|
|
|
const QString &t = templ.at(0).toQString();
|
2009-05-25 15:58:58 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProFileEvaluator::accept(ProFile *pro)
|
|
|
|
|
{
|
2010-06-18 13:30:03 +02:00
|
|
|
return d->visitProFile(pro, ProFileEvaluatorHandler::EvalProjectFile);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ProFileEvaluator::propertyValue(const QString &name) const
|
|
|
|
|
{
|
|
|
|
|
return d->propertyValue(name);
|
|
|
|
|
}
|
|
|
|
|
|
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
|