1 /* 2 * Copyright (c) 2011-2014, Intel Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation and/or 13 * other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software without 17 * specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 #pragma once 31 32 #include <vector> 33 #include "RemoteCommandHandler.h" 34 35 template <class CCommandParser> 36 class TRemoteCommandHandlerTemplate : public IRemoteCommandHandler 37 { 38 public: 39 /** Remote command parser execution return status */ 40 enum CommandStatus 41 { 42 EDone, /**< Command succeded, return "Done" */ 43 ESucceeded, /**< Command succeeded */ 44 EFailed, /**< Command failed */ 45 EShowUsage /**< Command failed, show usage */ 46 }; 47 48 /** Type of the remote command callbacks 49 * 50 * @param[in] remoteCommand contains the arguments of the received command. 51 * @param[out] strResult a string containing the result of the command. 52 * 53 * @return the command execution status, @see CommandStatus 54 */ 55 typedef CommandStatus (CCommandParser::*RemoteCommandParser)( 56 const IRemoteCommand &remoteCommand, std::string &strResult); 57 58 private: 59 // Parser descriptions 60 class CRemoteCommandParserItem 61 { 62 public: CRemoteCommandParserItem(const std::string & strCommandName,RemoteCommandParser pfnParser,size_t minArgumentCount,const std::string & strHelp,const std::string & strDescription)63 CRemoteCommandParserItem(const std::string &strCommandName, RemoteCommandParser pfnParser, 64 size_t minArgumentCount, const std::string &strHelp, 65 const std::string &strDescription) 66 : _strCommandName(strCommandName), _pfnParser(pfnParser), 67 _minArgumentCount(minArgumentCount), _strHelp(strHelp), 68 _strDescription(strDescription) 69 { 70 } 71 getCommandName()72 const std::string &getCommandName() const { return _strCommandName; } 73 getDescription()74 const std::string &getDescription() const { return _strDescription; } 75 76 // Usage usage()77 std::string usage() const { return _strCommandName + " " + _strHelp; } 78 parse(CCommandParser * pCommandParser,const IRemoteCommand & remoteCommand,std::string & strResult)79 bool parse(CCommandParser *pCommandParser, const IRemoteCommand &remoteCommand, 80 std::string &strResult) const 81 { 82 // Check enough arguments supplied 83 if (remoteCommand.getArgumentCount() < _minArgumentCount) { 84 85 strResult = std::string("Not enough arguments supplied\nUsage:\n") + usage(); 86 87 return false; 88 } 89 90 switch ((pCommandParser->*_pfnParser)(remoteCommand, strResult)) { 91 case EDone: 92 strResult = "Done"; 93 // Fall through intentionally 94 case ESucceeded: 95 return true; 96 case EShowUsage: 97 strResult = usage(); 98 // Fall through intentionally 99 case EFailed: 100 return false; 101 } 102 103 return false; 104 } 105 106 private: 107 std::string _strCommandName; 108 RemoteCommandParser _pfnParser; 109 size_t _minArgumentCount; 110 std::string _strHelp; 111 std::string _strDescription; 112 }; 113 114 public: TRemoteCommandHandlerTemplate(CCommandParser * pCommandParser)115 TRemoteCommandHandlerTemplate(CCommandParser *pCommandParser) 116 : _pCommandParser(pCommandParser), _maxCommandUsageLength(0) 117 { 118 // Help Command 119 addCommandParser("help", nullptr, 0, "", "Show commands description and usage"); 120 } ~TRemoteCommandHandlerTemplate()121 ~TRemoteCommandHandlerTemplate() override 122 { 123 // FIXME use unique_ptr 124 for (auto *parser : _remoteCommandParserVector) { 125 126 delete parser; 127 } 128 } 129 130 // Parsers addCommandParser(const std::string & strCommandName,RemoteCommandParser pfnParser,size_t minArgumentCount,const std::string & strHelp,const std::string & strDescription)131 bool addCommandParser(const std::string &strCommandName, RemoteCommandParser pfnParser, 132 size_t minArgumentCount, const std::string &strHelp, 133 const std::string &strDescription) 134 { 135 if (findCommandParserItem(strCommandName)) { 136 137 // Already exists 138 return false; 139 } 140 141 // Add command 142 _remoteCommandParserVector.push_back(new CRemoteCommandParserItem( 143 strCommandName, pfnParser, minArgumentCount, strHelp, strDescription)); 144 145 return true; 146 } 147 148 private: 149 // Command processing remoteCommandProcess(const IRemoteCommand & remoteCommand,std::string & strResult)150 bool remoteCommandProcess(const IRemoteCommand &remoteCommand, std::string &strResult) override 151 { 152 // Dispatch 153 const CRemoteCommandParserItem *pRemoteCommandParserItem = 154 findCommandParserItem(remoteCommand.getCommand()); 155 156 if (!pRemoteCommandParserItem) { 157 158 // Not found 159 strResult = "Command not found!\nUse \"help\" to show available commands"; 160 161 return false; 162 } 163 164 if (remoteCommand.getCommand() == "help") { 165 166 helpCommandProcess(strResult); 167 168 return true; 169 } 170 171 return pRemoteCommandParserItem->parse(_pCommandParser, remoteCommand, strResult); 172 } 173 174 // Max command usage length, use for formatting initMaxCommandUsageLength()175 void initMaxCommandUsageLength() 176 { 177 if (!_maxCommandUsageLength) { 178 // Show usages 179 for (const auto *pRemoteCommandParserItem : _remoteCommandParserVector) { 180 181 size_t remoteCommandUsageLength = pRemoteCommandParserItem->usage().length(); 182 183 if (remoteCommandUsageLength > _maxCommandUsageLength) { 184 185 _maxCommandUsageLength = remoteCommandUsageLength; 186 } 187 } 188 } 189 } 190 191 /////////////////// Remote command parsers 192 /// Help helpCommandProcess(std::string & strResult)193 void helpCommandProcess(std::string &strResult) 194 { 195 initMaxCommandUsageLength(); 196 197 // Show usages 198 for (const auto *pRemoteCommandParserItem : _remoteCommandParserVector) { 199 200 std::string strUsage = pRemoteCommandParserItem->usage(); 201 202 // Align 203 size_t spacesToAdd = _maxCommandUsageLength + 5 - strUsage.length(); 204 205 strResult += strUsage + std::string(spacesToAdd, ' ') + "=> " + 206 pRemoteCommandParserItem->getDescription() + '\n'; 207 } 208 } 209 findCommandParserItem(const std::string & strCommandName)210 const CRemoteCommandParserItem *findCommandParserItem(const std::string &strCommandName) const 211 { 212 for (const auto *pRemoteCommandParserItem : _remoteCommandParserVector) { 213 214 if (pRemoteCommandParserItem->getCommandName() == strCommandName) { 215 216 return pRemoteCommandParserItem; 217 } 218 } 219 return nullptr; 220 } 221 222 private: 223 CCommandParser *_pCommandParser; 224 std::vector<CRemoteCommandParserItem *> _remoteCommandParserVector; 225 size_t _maxCommandUsageLength; 226 }; 227