add $$str_member() function
just like $$member(), but operates on a string value rather than a list variable. it is the swiss army knife of cutting, providing equivalents of left(), right(), mid() and reverse() all in one. [ChangeLog][qmake] Added $$str_member() function. Change-Id: I7c7c6c971db402fff41b428d32a4451f45400728 Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io> Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io> Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
This commit is contained in:
parent
ba38926bbf
commit
e70330f99e
@ -2934,6 +2934,7 @@
|
|||||||
|
|
||||||
See also \l{upper(arg1 [, arg2 ..., argn])}{upper()}.
|
See also \l{upper(arg1 [, arg2 ..., argn])}{upper()}.
|
||||||
|
|
||||||
|
\target member()
|
||||||
\section2 member(variablename [, start [, end]])
|
\section2 member(variablename [, start [, end]])
|
||||||
|
|
||||||
Returns the slice of the list value of \c variablename with the
|
Returns the slice of the list value of \c variablename with the
|
||||||
@ -2960,6 +2961,9 @@
|
|||||||
that an empty list will be returned only when an index is invalid
|
that an empty list will be returned only when an index is invalid
|
||||||
(which is implied by the input variable being empty).
|
(which is implied by the input variable being empty).
|
||||||
|
|
||||||
|
See also \l{str_member()}.
|
||||||
|
|
||||||
|
\target num_add()
|
||||||
\section2 num_add(arg1 [, arg2 ..., argn])
|
\section2 num_add(arg1 [, arg2 ..., argn])
|
||||||
|
|
||||||
Takes an arbitrary number of numeric arguments and adds them up,
|
Takes an arbitrary number of numeric arguments and adds them up,
|
||||||
@ -3079,6 +3083,38 @@
|
|||||||
|
|
||||||
\snippet code/doc_src_qmake-manual.pro 168
|
\snippet code/doc_src_qmake-manual.pro 168
|
||||||
|
|
||||||
|
\target str_member()
|
||||||
|
\section2 str_member(arg [, start [, end]])
|
||||||
|
|
||||||
|
This function is identical to \l{member()}, except that it operates
|
||||||
|
on a string value instead of a list variable, and consequently the
|
||||||
|
indices refer to character positions.
|
||||||
|
|
||||||
|
This function can be used to implement many common string slicing
|
||||||
|
operations:
|
||||||
|
|
||||||
|
\code
|
||||||
|
# $$left(VAR, len)
|
||||||
|
left = $$str_member(VAR, 0, $$num_add($$len, -1))
|
||||||
|
|
||||||
|
# $$right(VAR, len)
|
||||||
|
right = $$str_member(VAR, -$$num, -1)
|
||||||
|
|
||||||
|
# $$mid(VAR, off, len)
|
||||||
|
mid = $$str_member(VAR, $$off, $$num_add($$off, $$len, -1))
|
||||||
|
|
||||||
|
# $$mid(VAR, off)
|
||||||
|
mid = $$str_member(VAR, $$off, -1)
|
||||||
|
|
||||||
|
# $$reverse(VAR)
|
||||||
|
reverse = $$str_member(VAR, -1, 0)
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\note In these implementations, a zero \c len argument needs to be
|
||||||
|
handled separately.
|
||||||
|
|
||||||
|
See also \l{member()}, \l{num_add()}.
|
||||||
|
|
||||||
\target str_size()
|
\target str_size()
|
||||||
\section2 str_size(arg)
|
\section2 str_size(arg)
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
#define fL1S(s) QString::fromLatin1(s)
|
#define fL1S(s) QString::fromLatin1(s)
|
||||||
|
|
||||||
enum ExpandFunc {
|
enum ExpandFunc {
|
||||||
E_INVALID = 0, E_MEMBER, E_FIRST, E_TAKE_FIRST, E_LAST, E_TAKE_LAST,
|
E_INVALID = 0, E_MEMBER, E_STR_MEMBER, E_FIRST, E_TAKE_FIRST, E_LAST, E_TAKE_LAST,
|
||||||
E_SIZE, E_STR_SIZE, E_CAT, E_FROMFILE, E_EVAL, E_LIST, E_SPRINTF, E_FORMAT_NUMBER,
|
E_SIZE, E_STR_SIZE, E_CAT, E_FROMFILE, E_EVAL, E_LIST, E_SPRINTF, E_FORMAT_NUMBER,
|
||||||
E_NUM_ADD, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
|
E_NUM_ADD, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
|
||||||
E_FIND, E_SYSTEM, E_UNIQUE, E_REVERSE, E_QUOTE, E_ESCAPE_EXPAND,
|
E_FIND, E_SYSTEM, E_UNIQUE, E_REVERSE, E_QUOTE, E_ESCAPE_EXPAND,
|
||||||
@ -105,6 +105,7 @@ void QMakeEvaluator::initFunctionStatics()
|
|||||||
const ExpandFunc func;
|
const ExpandFunc func;
|
||||||
} expandInits[] = {
|
} expandInits[] = {
|
||||||
{ "member", E_MEMBER },
|
{ "member", E_MEMBER },
|
||||||
|
{ "str_member", E_STR_MEMBER },
|
||||||
{ "first", E_FIRST },
|
{ "first", E_FIRST },
|
||||||
{ "take_first", E_TAKE_FIRST },
|
{ "take_first", E_TAKE_FIRST },
|
||||||
{ "last", E_LAST },
|
{ "last", E_LAST },
|
||||||
@ -202,6 +203,49 @@ static bool isTrue(const ProString &str)
|
|||||||
return !str.compare(statics.strtrue, Qt::CaseInsensitive) || str.toInt();
|
return !str.compare(statics.strtrue, Qt::CaseInsensitive) || str.toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
QMakeEvaluator::getMemberArgs(const ProKey &func, int srclen, const ProStringList &args,
|
||||||
|
int *start, int *end)
|
||||||
|
{
|
||||||
|
*start = 0, *end = 0;
|
||||||
|
if (args.count() >= 2) {
|
||||||
|
bool ok = true;
|
||||||
|
const ProString &start_str = args.at(1);
|
||||||
|
*start = start_str.toInt(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
if (args.count() == 2) {
|
||||||
|
int dotdot = start_str.indexOf(statics.strDotDot);
|
||||||
|
if (dotdot != -1) {
|
||||||
|
*start = start_str.left(dotdot).toInt(&ok);
|
||||||
|
if (ok)
|
||||||
|
*end = start_str.mid(dotdot+2).toInt(&ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
evalError(fL1S("%1() argument 2 (start) '%2' invalid.")
|
||||||
|
.arg(func.toQString(m_tmp1), start_str.toQString(m_tmp2)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*end = *start;
|
||||||
|
if (args.count() == 3)
|
||||||
|
*end = args.at(2).toInt(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
evalError(fL1S("%1() argument 3 (end) '%2' invalid.")
|
||||||
|
.arg(func.toQString(m_tmp1), args.at(2).toQString(m_tmp2)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*start < 0)
|
||||||
|
*start += srclen;
|
||||||
|
if (*end < 0)
|
||||||
|
*end += srclen;
|
||||||
|
if (*start < 0 || *start >= srclen || *end < 0 || *end >= srclen)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(Q_OS_WIN) && defined(PROEVALUATOR_FULL)
|
#if defined(Q_OS_WIN) && defined(PROEVALUATOR_FULL)
|
||||||
static QString windowsErrorCode()
|
static QString windowsErrorCode()
|
||||||
{
|
{
|
||||||
@ -660,47 +704,37 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
if (args.count() < 1 || args.count() > 3) {
|
if (args.count() < 1 || args.count() > 3) {
|
||||||
evalError(fL1S("member(var, start, end) requires one to three arguments."));
|
evalError(fL1S("member(var, start, end) requires one to three arguments."));
|
||||||
} else {
|
} else {
|
||||||
bool ok = true;
|
const ProStringList &src = values(map(args.at(0)));
|
||||||
const ProStringList &var = values(map(args.at(0)));
|
int start, end;
|
||||||
int start = 0, end = 0;
|
if (getMemberArgs(func, src.size(), args, &start, &end)) {
|
||||||
if (args.count() >= 2) {
|
ret.reserve(qAbs(end - start) + 1);
|
||||||
const ProString &start_str = args.at(1);
|
if (start < end) {
|
||||||
start = start_str.toInt(&ok);
|
for (int i = start; i <= end && src.size() >= i; i++)
|
||||||
if (!ok) {
|
ret += src.at(i);
|
||||||
if (args.count() == 2) {
|
|
||||||
int dotdot = start_str.indexOf(statics.strDotDot);
|
|
||||||
if (dotdot != -1) {
|
|
||||||
start = start_str.left(dotdot).toInt(&ok);
|
|
||||||
if (ok)
|
|
||||||
end = start_str.mid(dotdot+2).toInt(&ok);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ok)
|
|
||||||
evalError(fL1S("member() argument 2 (start) '%2' invalid.")
|
|
||||||
.arg(start_str.toQString(m_tmp1)));
|
|
||||||
} else {
|
} else {
|
||||||
end = start;
|
for (int i = start; i >= end && src.size() >= i && i >= 0; i--)
|
||||||
if (args.count() == 3)
|
ret += src.at(i);
|
||||||
end = args.at(2).toInt(&ok);
|
|
||||||
if (!ok)
|
|
||||||
evalError(fL1S("member() argument 3 (end) '%2' invalid.")
|
|
||||||
.arg(args.at(2).toQString(m_tmp1)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ok) {
|
}
|
||||||
if (start < 0)
|
break;
|
||||||
start += var.count();
|
case E_STR_MEMBER:
|
||||||
if (end < 0)
|
if (args.count() < 1 || args.count() > 3) {
|
||||||
end += var.count();
|
evalError(fL1S("str_member(str, start, end) requires one to three arguments."));
|
||||||
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 {
|
} else {
|
||||||
for (int i = start; i >= end && var.count() >= i && i >= 0; i--)
|
const ProString &src = args.at(0);
|
||||||
ret += var[i];
|
int start, end;
|
||||||
|
if (getMemberArgs(func, src.size(), args, &start, &end)) {
|
||||||
|
QString res;
|
||||||
|
res.reserve(qAbs(end - start) + 1);
|
||||||
|
if (start < end) {
|
||||||
|
for (int i = start; i <= end && src.size() >= i; i++)
|
||||||
|
res += src.at(i);
|
||||||
|
} else {
|
||||||
|
for (int i = start; i >= end && src.size() >= i && i >= 0; i--)
|
||||||
|
res += src.at(i);
|
||||||
}
|
}
|
||||||
|
ret += ProString(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -232,6 +232,9 @@ public:
|
|||||||
QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
|
QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
|
||||||
QMultiMap<int, ProString> &rootSet) const;
|
QMultiMap<int, ProString> &rootSet) const;
|
||||||
|
|
||||||
|
bool getMemberArgs(const ProKey &name, int srclen, const ProStringList &args,
|
||||||
|
int *start, int *end);
|
||||||
|
|
||||||
VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
|
VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
|
||||||
bool exe, const QString &contents);
|
bool exe, const QString &contents);
|
||||||
#ifndef QT_BOOTSTRAPPED
|
#ifndef QT_BOOTSTRAPPED
|
||||||
|
@ -718,6 +718,49 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir)
|
|||||||
<< "##:2: member() argument 2 (start) '4..foo' invalid."
|
<< "##:2: member() argument 2 (start) '4..foo' invalid."
|
||||||
<< true;
|
<< true;
|
||||||
|
|
||||||
|
// The argument processing is shared with $$member(), so some tests are skipped.
|
||||||
|
QTest::newRow("$$str_member(): empty")
|
||||||
|
<< "VAR = $$str_member()"
|
||||||
|
<< "VAR ="
|
||||||
|
<< ""
|
||||||
|
<< true;
|
||||||
|
|
||||||
|
QTest::newRow("$$str_member(): too short")
|
||||||
|
<< "VAR = $$str_member(string_value, 7, 12)"
|
||||||
|
<< "VAR =" // this is actually kinda stupid
|
||||||
|
<< ""
|
||||||
|
<< true;
|
||||||
|
|
||||||
|
QTest::newRow("$$str_member(): ok")
|
||||||
|
<< "VAR = $$str_member(string_value, 7, 11)"
|
||||||
|
<< "VAR = value"
|
||||||
|
<< ""
|
||||||
|
<< true;
|
||||||
|
|
||||||
|
QTest::newRow("$$str_member(): ok (default start)")
|
||||||
|
<< "VAR = $$str_member(string_value)"
|
||||||
|
<< "VAR = s"
|
||||||
|
<< ""
|
||||||
|
<< true;
|
||||||
|
|
||||||
|
QTest::newRow("$$str_member(): ok (default end)")
|
||||||
|
<< "VAR = $$str_member(string_value, 7)"
|
||||||
|
<< "VAR = v"
|
||||||
|
<< ""
|
||||||
|
<< true;
|
||||||
|
|
||||||
|
QTest::newRow("$$str_member(): negative")
|
||||||
|
<< "VAR = $$str_member(string_value, -5, -3)"
|
||||||
|
<< "VAR = val"
|
||||||
|
<< ""
|
||||||
|
<< true;
|
||||||
|
|
||||||
|
QTest::newRow("$$str_member(): inverse")
|
||||||
|
<< "VAR = $$str_member(string_value, -2, 1)"
|
||||||
|
<< "VAR = ulav_gnirt"
|
||||||
|
<< ""
|
||||||
|
<< true;
|
||||||
|
|
||||||
QTest::newRow("$$first(): empty")
|
QTest::newRow("$$first(): empty")
|
||||||
<< "IN = \nVAR = $$first(IN)"
|
<< "IN = \nVAR = $$first(IN)"
|
||||||
<< "VAR ="
|
<< "VAR ="
|
||||||
|
Loading…
x
Reference in New Issue
Block a user