Home | History | Annotate | Download | only in remote-processor
      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:
     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 
     72         const std::string &getCommandName() const { return _strCommandName; }
     73 
     74         const std::string &getDescription() const { return _strDescription; }
     75 
     76         // Usage
     77         std::string usage() const { return _strCommandName + " " + _strHelp; }
     78 
     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:
    115     TRemoteCommandHandlerTemplate(CCommandParser *pCommandParser)
    116         : _pCommandParser(pCommandParser), _maxCommandUsageLength(0)
    117     {
    118         // Help Command
    119         addCommandParser("help", NULL, 0, "", "Show commands description and usage");
    120     }
    121     ~TRemoteCommandHandlerTemplate()
    122     {
    123         // FIXME use unique_ptr
    124         for (auto *parser : _remoteCommandParserVector) {
    125 
    126             delete parser;
    127         }
    128     }
    129 
    130     // Parsers
    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
    150     bool remoteCommandProcess(const IRemoteCommand &remoteCommand, std::string &strResult)
    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
    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
    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 
    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 NULL;
    220     }
    221 
    222 private:
    223     CCommandParser *_pCommandParser;
    224     std::vector<CRemoteCommandParserItem *> _remoteCommandParserVector;
    225     size_t _maxCommandUsageLength;
    226 };
    227