2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2011-06-22 10:00:50 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2011-06-22 10:00:50 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2011-06-22 10:00:50 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:58:39 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2011-06-22 10:00:50 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2011-06-22 10:00:50 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2012-02-28 10:34:50 +01:00
|
|
|
|
2011-06-22 10:00:50 +02:00
|
|
|
#include "portlist.h"
|
|
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QPair>
|
|
|
|
|
#include <QString>
|
2013-03-18 14:47:33 +01:00
|
|
|
#include <QStringList>
|
2011-08-02 12:20:16 +02:00
|
|
|
|
2011-06-22 16:17:27 +02:00
|
|
|
#include <cctype>
|
|
|
|
|
|
2012-02-28 10:34:50 +01:00
|
|
|
namespace Utils {
|
2011-08-02 12:20:16 +02:00
|
|
|
namespace Internal {
|
2011-06-22 10:00:50 +02:00
|
|
|
namespace {
|
|
|
|
|
|
2016-04-19 16:43:30 +02:00
|
|
|
typedef QPair<Port, Port> Range;
|
2011-08-02 12:20:16 +02:00
|
|
|
|
2011-06-22 10:00:50 +02:00
|
|
|
class PortsSpecParser
|
|
|
|
|
{
|
|
|
|
|
struct ParseException {
|
|
|
|
|
ParseException(const char *error) : error(error) {}
|
|
|
|
|
const char * const error;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
PortsSpecParser(const QString &portsSpec)
|
|
|
|
|
: m_pos(0), m_portsSpec(portsSpec) { }
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Grammar: Spec -> [ ElemList ]
|
|
|
|
|
* ElemList -> Elem [ ',' ElemList ]
|
|
|
|
|
* Elem -> Port [ '-' Port ]
|
|
|
|
|
*/
|
|
|
|
|
PortList parse()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
if (!atEnd())
|
|
|
|
|
parseElemList();
|
2014-11-28 11:15:37 +01:00
|
|
|
} catch (const ParseException &e) {
|
2011-06-22 10:00:50 +02:00
|
|
|
qWarning("Malformed ports specification: %s", e.error);
|
|
|
|
|
}
|
|
|
|
|
return m_portList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void parseElemList()
|
|
|
|
|
{
|
|
|
|
|
if (atEnd())
|
|
|
|
|
throw ParseException("Element list empty.");
|
|
|
|
|
parseElem();
|
|
|
|
|
if (atEnd())
|
|
|
|
|
return;
|
|
|
|
|
if (nextChar() != ',') {
|
|
|
|
|
throw ParseException("Element followed by something else "
|
|
|
|
|
"than a comma.");
|
|
|
|
|
}
|
|
|
|
|
++m_pos;
|
|
|
|
|
parseElemList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void parseElem()
|
|
|
|
|
{
|
2016-04-19 16:43:30 +02:00
|
|
|
const Port startPort = parsePort();
|
2011-06-22 10:00:50 +02:00
|
|
|
if (atEnd() || nextChar() != '-') {
|
|
|
|
|
m_portList.addPort(startPort);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
++m_pos;
|
2016-04-19 16:43:30 +02:00
|
|
|
const Port endPort = parsePort();
|
2011-06-22 10:00:50 +02:00
|
|
|
if (endPort < startPort)
|
|
|
|
|
throw ParseException("Invalid range (end < start).");
|
|
|
|
|
m_portList.addRange(startPort, endPort);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-19 16:43:30 +02:00
|
|
|
Port parsePort()
|
2011-06-22 10:00:50 +02:00
|
|
|
{
|
|
|
|
|
if (atEnd())
|
|
|
|
|
throw ParseException("Empty port string.");
|
|
|
|
|
int port = 0;
|
|
|
|
|
do {
|
|
|
|
|
const char next = nextChar();
|
|
|
|
|
if (!std::isdigit(next))
|
|
|
|
|
break;
|
|
|
|
|
port = 10*port + next - '0';
|
|
|
|
|
++m_pos;
|
|
|
|
|
} while (!atEnd());
|
|
|
|
|
if (port == 0 || port >= 2 << 16)
|
|
|
|
|
throw ParseException("Invalid port value.");
|
2016-04-19 16:43:30 +02:00
|
|
|
return Port(port);
|
2011-06-22 10:00:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool atEnd() const { return m_pos == m_portsSpec.length(); }
|
2012-09-21 13:54:38 +02:00
|
|
|
char nextChar() const { return m_portsSpec.at(m_pos).toLatin1(); }
|
2011-06-22 10:00:50 +02:00
|
|
|
|
|
|
|
|
PortList m_portList;
|
|
|
|
|
int m_pos;
|
|
|
|
|
const QString &m_portsSpec;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
2011-08-02 12:20:16 +02:00
|
|
|
class PortListPrivate
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
QList<Range> ranges;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
|
2011-09-15 09:10:10 +02:00
|
|
|
PortList::PortList() : d(new Internal::PortListPrivate)
|
2011-08-02 12:20:16 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-15 09:10:10 +02:00
|
|
|
PortList::PortList(const PortList &other) : d(new Internal::PortListPrivate(*other.d))
|
2011-08-02 12:20:16 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-14 12:05:23 +01:00
|
|
|
PortList::~PortList()
|
|
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-02 12:20:16 +02:00
|
|
|
PortList &PortList::operator=(const PortList &other)
|
|
|
|
|
{
|
2011-09-15 09:10:10 +02:00
|
|
|
*d = *other.d;
|
2011-08-02 12:20:16 +02:00
|
|
|
return *this;
|
|
|
|
|
}
|
2011-06-22 10:00:50 +02:00
|
|
|
|
|
|
|
|
PortList PortList::fromString(const QString &portsSpec)
|
|
|
|
|
{
|
2011-08-02 12:20:16 +02:00
|
|
|
return Internal::PortsSpecParser(portsSpec).parse();
|
2011-06-22 10:00:50 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-19 16:43:30 +02:00
|
|
|
void PortList::addPort(Port port) { addRange(port, port); }
|
2011-06-22 10:00:50 +02:00
|
|
|
|
2016-04-19 16:43:30 +02:00
|
|
|
void PortList::addRange(Port startPort, Port endPort)
|
2011-06-22 10:00:50 +02:00
|
|
|
{
|
2011-09-15 09:10:10 +02:00
|
|
|
d->ranges << Internal::Range(startPort, endPort);
|
2011-06-22 10:00:50 +02:00
|
|
|
}
|
|
|
|
|
|
2011-09-15 09:10:10 +02:00
|
|
|
bool PortList::hasMore() const { return !d->ranges.isEmpty(); }
|
2011-06-22 10:00:50 +02:00
|
|
|
|
2016-04-19 16:43:30 +02:00
|
|
|
bool PortList::contains(Port port) const
|
2011-09-08 10:15:38 +02:00
|
|
|
{
|
2011-09-15 09:10:10 +02:00
|
|
|
foreach (const Internal::Range &r, d->ranges) {
|
2011-09-08 10:15:38 +02:00
|
|
|
if (port >= r.first && port <= r.second)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-22 10:00:50 +02:00
|
|
|
int PortList::count() const
|
|
|
|
|
{
|
|
|
|
|
int n = 0;
|
2011-09-15 09:10:10 +02:00
|
|
|
foreach (const Internal::Range &r, d->ranges)
|
2016-04-19 16:43:30 +02:00
|
|
|
n += r.second.number() - r.first.number() + 1;
|
2011-06-22 10:00:50 +02:00
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-19 16:43:30 +02:00
|
|
|
Port PortList::getNext()
|
2011-06-22 10:00:50 +02:00
|
|
|
{
|
2011-09-15 09:10:10 +02:00
|
|
|
Q_ASSERT(!d->ranges.isEmpty());
|
2011-08-02 12:20:16 +02:00
|
|
|
|
2011-09-15 09:10:10 +02:00
|
|
|
Internal::Range &firstRange = d->ranges.first();
|
2016-04-19 16:43:30 +02:00
|
|
|
const Port next = firstRange.first;
|
|
|
|
|
firstRange.first = Port(firstRange.first.number() + 1);
|
2011-06-22 10:00:50 +02:00
|
|
|
if (firstRange.first > firstRange.second)
|
2011-09-15 09:10:10 +02:00
|
|
|
d->ranges.removeFirst();
|
2011-06-22 10:00:50 +02:00
|
|
|
return next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString PortList::toString() const
|
|
|
|
|
{
|
|
|
|
|
QString stringRep;
|
2011-09-15 09:10:10 +02:00
|
|
|
foreach (const Internal::Range &range, d->ranges) {
|
2016-04-19 16:43:30 +02:00
|
|
|
stringRep += QString::number(range.first.number());
|
2011-06-22 10:00:50 +02:00
|
|
|
if (range.second != range.first)
|
2016-04-19 16:43:30 +02:00
|
|
|
stringRep += QLatin1Char('-') + QString::number(range.second.number());
|
2011-06-22 10:00:50 +02:00
|
|
|
stringRep += QLatin1Char(',');
|
|
|
|
|
}
|
|
|
|
|
if (!stringRep.isEmpty())
|
|
|
|
|
stringRep.remove(stringRep.length() - 1, 1); // Trailing comma.
|
|
|
|
|
return stringRep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString PortList::regularExpression()
|
|
|
|
|
{
|
|
|
|
|
const QLatin1String portExpr("(\\d)+");
|
|
|
|
|
const QString listElemExpr = QString::fromLatin1("%1(-%1)?").arg(portExpr);
|
|
|
|
|
return QString::fromLatin1("((%1)(,%1)*)?").arg(listElemExpr);
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-28 10:34:50 +01:00
|
|
|
} // namespace Utils
|