You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
7.6 KiB
227 lines
7.6 KiB
/*
|
|
* 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;
|
|
};
|