/* * 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", NULL, 0, "", "Show commands description and usage"); } ~TRemoteCommandHandlerTemplate() { // 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) { // 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 NULL; } private: CCommandParser *_pCommandParser; std::vector<CRemoteCommandParserItem *> _remoteCommandParserVector; size_t _maxCommandUsageLength; };