From fe2fa65d36900a77ac2e05d14abd0013ccf9a09b Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Wed, 29 Oct 2014 01:25:09 +0100 Subject: [PATCH] refs #77, a simple command parser * more a util class, not a real parser --- src/blackmisc/simplecommandparser.cpp | 148 ++++++++++++++++++++++++++ src/blackmisc/simplecommandparser.h | 89 ++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 src/blackmisc/simplecommandparser.cpp create mode 100644 src/blackmisc/simplecommandparser.h diff --git a/src/blackmisc/simplecommandparser.cpp b/src/blackmisc/simplecommandparser.cpp new file mode 100644 index 000000000..2c09c2425 --- /dev/null +++ b/src/blackmisc/simplecommandparser.cpp @@ -0,0 +1,148 @@ +/* Copyright (C) 2013 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "simplecommandparser.h" + +namespace BlackMisc +{ + + CSimpleCommandParser::CSimpleCommandParser(const QStringList &knownCommands) + { + this->setCheckedCommandList(knownCommands); + } + + void CSimpleCommandParser::parse(const QString &commandLine) + { + this->m_originalLine = commandLine; + this->m_cleanedLine = commandLine.trimmed().simplified(); + if (!this->m_cleanedLine.isEmpty()) + { + this->m_splitParts = m_cleanedLine.split(' '); + if (!this->m_splitParts.isEmpty()) + { + const QString first = this->m_splitParts.first(); + const QString formatted = formatCommand(first); + if (isCommand(first)) + { + this->m_commandPart = formatCommand(first); + this->m_knownCommand = this->m_knownCommands.contains(formatted); + } + } + } + } + + const QString &CSimpleCommandParser::part(int index) const + { + static const QString empty(""); + if (index < 0 || index >= this->m_splitParts.size()) return empty; + return this->m_splitParts.at(index); + } + + QString CSimpleCommandParser::remainingStringAfter(int index) const + { + if (index < 0) { return this->m_originalLine.trimmed(); } + QString p = this->part(index); + int fi = this->m_originalLine.indexOf(p, 0, Qt::CaseInsensitive); + if (fi < 0) return ""; + return this->m_originalLine.right(fi + p.length()).trimmed(); + } + + int CSimpleCommandParser::countParts() const + { + return this->m_splitParts.count(); + } + + int CSimpleCommandParser::countPartsWithoutCommand() const + { + int c = countParts(); + return c > 0 ? c - 1 : 0; + } + + bool CSimpleCommandParser::isInt(int index) const + { + const QString p = this->part(index); + if (p.isEmpty()) return false; + bool ok; + p.toInt(&ok); + return ok; + } + + bool CSimpleCommandParser::isDouble(int index) const + { + const QString p = this->part(index); + if (p.isEmpty()) return false; + bool ok; + p.toDouble(&ok); + return ok; + } + + int CSimpleCommandParser::toInt(int index, int def) const + { + const QString p = this->part(index); + if (p.isEmpty()) return def; + bool ok; + int i = p.toInt(&ok); + return ok ? i : def; + } + + double CSimpleCommandParser::toDouble(int index, double def) const + { + const QString p = this->part(index); + if (p.isEmpty()) return def; + bool ok; + double d = p.toDouble(&ok); + return ok ? d : def; + } + + QString CSimpleCommandParser::removeLeadingDot(const QString &candidate) + { + if (!candidate.startsWith('.')) { return candidate; } + return candidate.right(candidate.length() - 1); + } + + QString CSimpleCommandParser::formatCommand(const QString &command) + { + return removeLeadingDot(command.trimmed().toLower()); + } + + bool CSimpleCommandParser::isCommand(const QString &candidate) + { + return candidate.startsWith('.'); + } + + bool CSimpleCommandParser::matchesCommand(const QString &checkCommand, const QString &alias1, const QString &alias2) + { + if (this->m_commandPart.isEmpty()) { return false; } + if (!checkCommand.isEmpty() && formatCommand(checkCommand) == this->m_commandPart) { return true; } + if (!alias1.isEmpty() && formatCommand(alias1) == this->m_commandPart) { return true; } + if (!alias2.isEmpty() && formatCommand(alias2) == this->m_commandPart) { return true; } + return false; + } + + bool CSimpleCommandParser::commandStartsWith(const QString &startPattern) const + { + if (this->m_commandPart.isEmpty()) { return false; } + return this->m_commandPart.startsWith(formatCommand(startPattern)); + } + + bool CSimpleCommandParser::commandEndsWith(const QString &endPattern) const + { + if (this->m_commandPart.isEmpty()) { return false; } + return this->m_commandPart.endsWith(endPattern); + } + + void CSimpleCommandParser::setCheckedCommandList(const QStringList &commands) + { + foreach(QString c, commands) + { + this->m_knownCommands.append(formatCommand(c)); + } + } + +} // namespace diff --git a/src/blackmisc/simplecommandparser.h b/src/blackmisc/simplecommandparser.h new file mode 100644 index 000000000..19697b608 --- /dev/null +++ b/src/blackmisc/simplecommandparser.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2013 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_SIMPLECOMMANDPARSER_H +#define BLACKMISC_SIMPLECOMMANDPARSER_H + +#include +#include + +namespace BlackMisc +{ + //! Utility methods for simple line parsing used with the command line + //! \remarks case insensitive parsing, commands start with . as ".msg" + class CSimpleCommandParser + { + public: + //! No Constructor + CSimpleCommandParser(const QStringList &knownCommands); + + //! Known command + bool isKnownCommand() const { return m_knownCommand; } + + //! Parse + void parse(const QString &commandLine); + + //! Is given command current command of command line + bool matchesCommand(const QString &checkCommand, const QString &alias1 = "", const QString &alias2 = ""); + + //! Command starting with pattern? + bool commandStartsWith(const QString &startPattern) const; + + //! Command ending with pattern? + bool commandEndsWith(const QString &endPattern) const; + + //! Get part, 0 is command itself + const QString &part(int index) const; + + //! Remaining part after + QString remainingStringAfter(int index) const; + + //! Count parts + int countParts() const; + + //! Count parts, command excluded + int countPartsWithoutCommand() const; + + //! Is part an integer? + bool isInt(int index) const; + + //! Is part a double? + bool isDouble(int index) const; + + //! Part as integer + int toInt(int index, int def = -1) const; + + //! Part as double + double toDouble(int index, double def = -1.0) const; + + private: + QString m_originalLine; + QString m_cleanedLine; //!< trimmed, no double spaces etc. + QString m_commandPart; //!< command part (e.g. ".msg", if any) + QStringList m_splitParts; //!< split parts (split by " ") + QStringList m_knownCommands; //!< known / handled commands + bool m_knownCommand = false; //!< known command + + //! Avoid wrong usage + void setCheckedCommandList(const QStringList &commands); + + //! Remove leading dot: ".msg" -> "msg" + static QString removeLeadingDot(const QString &candidate); + + //! Clean up a command string + static QString formatCommand(const QString &command); + + //! Command, aka as starts with dot + static bool isCommand(const QString &candidate); + }; +} + +#endif // guard