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 35template <class CCommandParser> 36class TRemoteCommandHandlerTemplate : public IRemoteCommandHandler 37{ 38public: 39 /** Remote command parser execution return status */ 40 enum CommandStatus { 41 EDone, /**< Command succeded, return "Done" */ 42 ESucceeded, /**< Command succeeded */ 43 EFailed, /**< Command failed */ 44 EShowUsage /**< Command failed, show usage */ 45 }; 46 47 /** Type of the remote command callbacks 48 * 49 * @param[in] remoteCommand contains the arguments of the received command. 50 * @param[out] strResult a string containing the result of the command. 51 * 52 * @return the command execution status, @see CommandStatus 53 */ 54 typedef CommandStatus (CCommandParser::*RemoteCommandParser)(const IRemoteCommand& remoteCommand, std::string& strResult); 55 56private: 57 // Parser descriptions 58 class CRemoteCommandParserItem 59 { 60 public: 61 CRemoteCommandParserItem(const std::string& strCommandName, 62 RemoteCommandParser pfnParser, 63 uint32_t uiMinArgumentCount, 64 const std::string& strHelp, 65 const std::string& strDescription) 66 : _strCommandName(strCommandName), 67 _pfnParser(pfnParser), 68 _uiMinArgumentCount(uiMinArgumentCount), 69 _strHelp(strHelp), 70 _strDescription(strDescription) {} 71 72 const std::string& getCommandName() const 73 { 74 return _strCommandName; 75 } 76 77 const std::string& getDescription() const 78 { 79 return _strDescription; 80 } 81 82 // Usage 83 std::string usage() const 84 { 85 return _strCommandName + " " + _strHelp; 86 } 87 88 bool parse(CCommandParser* pCommandParser, const IRemoteCommand& remoteCommand, std::string& strResult) const 89 { 90 // Check enough arguments supplied 91 if (remoteCommand.getArgumentCount() < _uiMinArgumentCount) { 92 93 strResult = std::string("Not enough arguments supplied\nUsage:\n") + usage(); 94 95 return false; 96 } 97 98 switch ((pCommandParser->*_pfnParser)(remoteCommand, strResult)) { 99 case EDone: 100 strResult = "Done"; 101 // Fall through intentionally 102 case ESucceeded: 103 return true; 104 case EShowUsage: 105 strResult = usage(); 106 // Fall through intentionally 107 case EFailed: 108 return false; 109 } 110 111 return false; 112 } 113 114 private: 115 std::string _strCommandName; 116 RemoteCommandParser _pfnParser; 117 uint32_t _uiMinArgumentCount; 118 std::string _strHelp; 119 std::string _strDescription; 120 }; 121 122public: 123 TRemoteCommandHandlerTemplate(CCommandParser* pCommandParser) : _pCommandParser(pCommandParser), _uiMaxCommandUsageLength(0) 124 { 125 // Help Command 126 addCommandParser("help", NULL, 0, "", "Show commands description and usage"); 127 } 128 ~TRemoteCommandHandlerTemplate() 129 { 130 uint32_t uiIndex; 131 132 for (uiIndex = 0; uiIndex < _remoteCommandParserVector.size(); uiIndex++) { 133 134 delete _remoteCommandParserVector[uiIndex]; 135 } 136 } 137 138 // Parsers 139 bool addCommandParser(const std::string& strCommandName, 140 RemoteCommandParser pfnParser, 141 uint32_t uiMinArgumentCount, 142 const std::string& strHelp, 143 const std::string& strDescription) 144 { 145 if (findCommandParserItem(strCommandName)) { 146 147 // Already exists 148 return false; 149 } 150 151 // Add command 152 _remoteCommandParserVector.push_back(new CRemoteCommandParserItem(strCommandName, pfnParser, uiMinArgumentCount, strHelp, strDescription)); 153 154 return true; 155 } 156 157private: 158 // Command processing 159 bool remoteCommandProcess(const IRemoteCommand& remoteCommand, std::string& strResult) 160 { 161 // Dispatch 162 const CRemoteCommandParserItem* pRemoteCommandParserItem = findCommandParserItem(remoteCommand.getCommand()); 163 164 if (!pRemoteCommandParserItem) { 165 166 // Not found 167 strResult = "Command not found!\nUse \"help\" to show available commands"; 168 169 return false; 170 } 171 172 if (remoteCommand.getCommand() == "help") { 173 174 helpCommandProcess(strResult); 175 176 return true; 177 } 178 179 return pRemoteCommandParserItem->parse(_pCommandParser, remoteCommand, strResult); 180 } 181 182 // Max command usage length, use for formatting 183 void initMaxCommandUsageLength() 184 { 185 if (!_uiMaxCommandUsageLength) { 186 // Show usages 187 uint32_t uiIndex; 188 189 for (uiIndex = 0; uiIndex < _remoteCommandParserVector.size(); uiIndex++) { 190 191 const CRemoteCommandParserItem* pRemoteCommandParserItem = _remoteCommandParserVector[uiIndex]; 192 193 uint32_t uiRemoteCommandUsageLength = (uint32_t)pRemoteCommandParserItem->usage().length(); 194 195 if (uiRemoteCommandUsageLength > _uiMaxCommandUsageLength) { 196 197 _uiMaxCommandUsageLength = uiRemoteCommandUsageLength; 198 } 199 } 200 } 201 } 202 203 /////////////////// Remote command parsers 204 /// Help 205 void helpCommandProcess(std::string& strResult) 206 { 207 initMaxCommandUsageLength(); 208 209 strResult = "\n"; 210 211 // Show usages 212 uint32_t uiIndex; 213 214 for (uiIndex = 0; uiIndex < _remoteCommandParserVector.size(); uiIndex++) { 215 216 const CRemoteCommandParserItem* pRemoteCommandParserItem = _remoteCommandParserVector[uiIndex]; 217 218 std::string strUsage = pRemoteCommandParserItem->usage(); 219 220 strResult += strUsage; 221 222 // Align 223 uint32_t uiToSpacesAdd = _uiMaxCommandUsageLength + 5 - (uint32_t)strUsage.length(); 224 225 while (uiToSpacesAdd--) { 226 227 strResult += " "; 228 } 229 230 strResult += std::string("=> ") + std::string(pRemoteCommandParserItem->getDescription()) + "\n"; 231 } 232 } 233 234 const CRemoteCommandParserItem* findCommandParserItem(const std::string& strCommandName) const 235 { 236 uint32_t uiIndex; 237 238 for (uiIndex = 0; uiIndex < _remoteCommandParserVector.size(); uiIndex++) { 239 240 const CRemoteCommandParserItem* pRemoteCommandParserItem = _remoteCommandParserVector[uiIndex]; 241 242 if (pRemoteCommandParserItem->getCommandName() == strCommandName) { 243 244 return pRemoteCommandParserItem; 245 } 246 } 247 return NULL; 248 } 249 250private: 251 CCommandParser* _pCommandParser; 252 std::vector<CRemoteCommandParserItem*> _remoteCommandParserVector; 253 uint32_t _uiMaxCommandUsageLength; 254}; 255 256