blob: 000ab7015223fe31ff0d3c704468d7fc5d44de8e [file] [log] [blame]
David Wagnerb76c9d62014-02-05 18:30:24 +01001/*
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 */
Patrick Benavolicfb64dd2011-10-24 18:50:03 +020030#pragma once
31
32#include <vector>
33#include "RemoteCommandHandler.h"
34
35template <class CCommandParser>
36class TRemoteCommandHandlerTemplate : public IRemoteCommandHandler
37{
38public:
Kevin Rocard325bf972013-07-18 09:13:51 +020039 /** Remote command parser execution return status */
Patrick Benavolicfb64dd2011-10-24 18:50:03 +020040 enum CommandStatus {
Kevin Rocard2c2b20a2013-09-06 11:50:27 +020041 EDone, /**< Command succeded, return "Done" */
42 ESucceeded, /**< Command succeeded */
43 EFailed, /**< Command failed */
44 EShowUsage /**< Command failed, show usage */
Patrick Benavolicfb64dd2011-10-24 18:50:03 +020045 };
46
Kevin Rocard325bf972013-07-18 09:13:51 +020047 /** 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 */
Patrick Benavolicfb64dd2011-10-24 18:50:03 +020054 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!";
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 = 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 - 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};
Sebastien Gonzalved7e48442013-03-12 14:30:27 +0100255