| /* | |
| * Copyright (c) 2011-2014, Intel Corporation | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without modification, | |
| * are permitted provided that the following conditions are met: | |
| * | |
| * 1. Redistributions of source code must retain the above copyright notice, this | |
| * list of conditions and the following disclaimer. | |
| * | |
| * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| * this list of conditions and the following disclaimer in the documentation and/or | |
| * other materials provided with the distribution. | |
| * | |
| * 3. Neither the name of the copyright holder nor the names of its contributors | |
| * may be used to endorse or promote products derived from this software without | |
| * specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #pragma once | |
| #include <vector> | |
| #include "RemoteCommandHandler.h" | |
| template <class CCommandParser> | |
| class TRemoteCommandHandlerTemplate : public IRemoteCommandHandler | |
| { | |
| public: | |
| /** Remote command parser execution return status */ | |
| enum CommandStatus | |
| { | |
| EDone, /**< Command succeded, return "Done" */ | |
| ESucceeded, /**< Command succeeded */ | |
| EFailed, /**< Command failed */ | |
| EShowUsage /**< Command failed, show usage */ | |
| }; | |
| /** Type of the remote command callbacks | |
| * | |
| * @param[in] remoteCommand contains the arguments of the received command. | |
| * @param[out] strResult a string containing the result of the command. | |
| * | |
| * @return the command execution status, @see CommandStatus | |
| */ | |
| typedef CommandStatus (CCommandParser::*RemoteCommandParser)( | |
| const IRemoteCommand &remoteCommand, std::string &strResult); | |
| private: | |
| // Parser descriptions | |
| class CRemoteCommandParserItem | |
| { | |
| public: | |
| CRemoteCommandParserItem(const std::string &strCommandName, RemoteCommandParser pfnParser, | |
| size_t minArgumentCount, const std::string &strHelp, | |
| const std::string &strDescription) | |
| : _strCommandName(strCommandName), _pfnParser(pfnParser), | |
| _minArgumentCount(minArgumentCount), _strHelp(strHelp), | |
| _strDescription(strDescription) | |
| { | |
| } | |
| const std::string &getCommandName() const { return _strCommandName; } | |
| const std::string &getDescription() const { return _strDescription; } | |
| // Usage | |
| std::string usage() const { return _strCommandName + " " + _strHelp; } | |
| bool parse(CCommandParser *pCommandParser, const IRemoteCommand &remoteCommand, | |
| std::string &strResult) const | |
| { | |
| // Check enough arguments supplied | |
| if (remoteCommand.getArgumentCount() < _minArgumentCount) { | |
| strResult = std::string("Not enough arguments supplied\nUsage:\n") + usage(); | |
| return false; | |
| } | |
| switch ((pCommandParser->*_pfnParser)(remoteCommand, strResult)) { | |
| case EDone: | |
| strResult = "Done"; | |
| // Fall through intentionally | |
| case ESucceeded: | |
| return true; | |
| case EShowUsage: | |
| strResult = usage(); | |
| // Fall through intentionally | |
| case EFailed: | |
| return false; | |
| } | |
| return false; | |
| } | |
| private: | |
| std::string _strCommandName; | |
| RemoteCommandParser _pfnParser; | |
| size_t _minArgumentCount; | |
| std::string _strHelp; | |
| std::string _strDescription; | |
| }; | |
| public: | |
| TRemoteCommandHandlerTemplate(CCommandParser *pCommandParser) | |
| : _pCommandParser(pCommandParser), _maxCommandUsageLength(0) | |
| { | |
| // Help Command | |
| addCommandParser("help", nullptr, 0, "", "Show commands description and usage"); | |
| } | |
| ~TRemoteCommandHandlerTemplate() override | |
| { | |
| // FIXME use unique_ptr | |
| for (auto *parser : _remoteCommandParserVector) { | |
| delete parser; | |
| } | |
| } | |
| // Parsers | |
| bool addCommandParser(const std::string &strCommandName, RemoteCommandParser pfnParser, | |
| size_t minArgumentCount, const std::string &strHelp, | |
| const std::string &strDescription) | |
| { | |
| if (findCommandParserItem(strCommandName)) { | |
| // Already exists | |
| return false; | |
| } | |
| // Add command | |
| _remoteCommandParserVector.push_back(new CRemoteCommandParserItem( | |
| strCommandName, pfnParser, minArgumentCount, strHelp, strDescription)); | |
| return true; | |
| } | |
| private: | |
| // Command processing | |
| bool remoteCommandProcess(const IRemoteCommand &remoteCommand, std::string &strResult) override | |
| { | |
| // Dispatch | |
| const CRemoteCommandParserItem *pRemoteCommandParserItem = | |
| findCommandParserItem(remoteCommand.getCommand()); | |
| if (!pRemoteCommandParserItem) { | |
| // Not found | |
| strResult = "Command not found!\nUse \"help\" to show available commands"; | |
| return false; | |
| } | |
| if (remoteCommand.getCommand() == "help") { | |
| helpCommandProcess(strResult); | |
| return true; | |
| } | |
| return pRemoteCommandParserItem->parse(_pCommandParser, remoteCommand, strResult); | |
| } | |
| // Max command usage length, use for formatting | |
| void initMaxCommandUsageLength() | |
| { | |
| if (!_maxCommandUsageLength) { | |
| // Show usages | |
| for (const auto *pRemoteCommandParserItem : _remoteCommandParserVector) { | |
| size_t remoteCommandUsageLength = pRemoteCommandParserItem->usage().length(); | |
| if (remoteCommandUsageLength > _maxCommandUsageLength) { | |
| _maxCommandUsageLength = remoteCommandUsageLength; | |
| } | |
| } | |
| } | |
| } | |
| /////////////////// Remote command parsers | |
| /// Help | |
| void helpCommandProcess(std::string &strResult) | |
| { | |
| initMaxCommandUsageLength(); | |
| // Show usages | |
| for (const auto *pRemoteCommandParserItem : _remoteCommandParserVector) { | |
| std::string strUsage = pRemoteCommandParserItem->usage(); | |
| // Align | |
| size_t spacesToAdd = _maxCommandUsageLength + 5 - strUsage.length(); | |
| strResult += strUsage + std::string(spacesToAdd, ' ') + "=> " + | |
| pRemoteCommandParserItem->getDescription() + '\n'; | |
| } | |
| } | |
| const CRemoteCommandParserItem *findCommandParserItem(const std::string &strCommandName) const | |
| { | |
| for (const auto *pRemoteCommandParserItem : _remoteCommandParserVector) { | |
| if (pRemoteCommandParserItem->getCommandName() == strCommandName) { | |
| return pRemoteCommandParserItem; | |
| } | |
| } | |
| return nullptr; | |
| } | |
| private: | |
| CCommandParser *_pCommandParser; | |
| std::vector<CRemoteCommandParserItem *> _remoteCommandParserVector; | |
| size_t _maxCommandUsageLength; | |
| }; |