text: /*
     +----------------------------------------------------------------------+
     | HipHop for PHP                                                       |
     +----------------------------------------------------------------------+
     | Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com)     |
     +----------------------------------------------------------------------+
     | This source file is subject to version 3.01 of the PHP license,      |
     | that is bundled with this package in the file LICENSE, and is        |
     | available through the world-wide-web at the following url:           |
     | http://www.php.net/license/3_01.txt                                  |
     | If you did not receive a copy of the PHP license and are unable to   |
     | obtain it through the world-wide-web, please send a note to          |
     | license@php.net so we can mail you a copy immediately.               |
     +----------------------------------------------------------------------+
  */
  
  #ifndef incl_HPHP_EVAL_DEBUGGER_COMMAND_H_
  #define incl_HPHP_EVAL_DEBUGGER_COMMAND_H_
  
  #include <memory>
  #include <string>
  
  #include "hphp/runtime/base/type-string.h"
  
  namespace HPHP {
  ///////////////////////////////////////////////////////////////////////////////
  
  struct DebuggerThriftBuffer;
  
  namespace Eval {
  ///////////////////////////////////////////////////////////////////////////////
  
  struct DebuggerClient;
  struct DebuggerProxy;
  
  struct DebuggerCommand;
  using DebuggerCommandPtr = std::shared_ptr<DebuggerCommand>;
  
  /*
   * DebuggerCommand is the base of all commands executed by the debugger. It
   * also represents the base binary communication format between DebuggerProxy
   * and DebuggerClient.
   *
   * Each command has serialization logic, plus client- and server-side logic.
   * Client-side logic is implemented in the onClient* methods, while server-side
   * is in the onServer* methods.
   */
  struct DebuggerCommand {
    /*
     * Warning: Do NOT modify exists values, as they are used in binary network
     * protocol, and changing them may create incompatibility between different
     * versions of debugger and server!
     */
    enum Type {
      KindOfNone                = 0,
      // Now I sing my A, B, C...
      KindOfAbort               = 1,
      KindOfBreak               = 2,
      KindOfContinue            = 3,
      KindOfDown                = 4,
      KindOfException           = 5,
      KindOfFrame               = 6,
      KindOfGlobal              = 7,
      KindOfHelp                = 8,
      KindOfInfo                = 9,
      KindOfConstant            = 11,
      KindOfList                = 12,
      KindOfMachine             = 13,
      KindOfNext                = 14,
      KindOfOut                 = 15,
      KindOfPrint               = 16,
      KindOfQuit                = 17,
      KindOfRun                 = 18,
      KindOfStep                = 19,
      KindOfThread              = 20,
      KindOfUp                  = 21,
      KindOfVariable            = 22,
      KindOfVariableAsync       = 222,
      KindOfWhere               = 23,
      KindOfWhereAsync          = 223,
      KindOfExtended            = 24,
      KindOfComplete            = 27,
  
      KindOfEval                = 1000,
      KindOfShell               = 1001,
      KindOfMacro               = 1002,
      KindOfConfig              = 1003,
      KindOfInstrument          = 1004,
  
      // DebuggerProxy -> DebuggerClient
      KindOfInterrupt           = 10000,
      KindOfSignal              = 10001,
  
      // Internal testing only
      KindOfInternalTesting     = 20000, // The real test command
      KindOfInternalTestingBad  = 20001, // A command type we never recgonize
    };
  
    static bool Receive(DebuggerThriftBuffer &thrift, DebuggerCommandPtr &cmd,
                        const char *caller);
  
  public:
    explicit DebuggerCommand(Type type): m_type(type) {}
    virtual ~DebuggerCommand() {}
  
    bool is(Type type) const {
      return m_type == type;
    }
  
    Type getType() const {
      return m_type;
    }
  
    bool send(DebuggerThriftBuffer&);
    bool recv(DebuggerThriftBuffer&);
  
    virtual void list(DebuggerClient&);
    virtual void help(DebuggerClient&);
  
    virtual void onClient(DebuggerClient&) = 0;
    virtual bool onServer(DebuggerProxy&);
  
    // Returns true if DebuggerProxy::processInterrupt() should return
    // to its caller instead of processing further commands from the client.
    bool shouldExitInterrupt() const {
      return m_exitInterrupt;
    }
  
    // Returns a non empty error message if the receipt of this command
    // did not complete successfully.
    const std::string& getWireError() const {
      return m_wireError;
    }
  
  protected:
    bool displayedHelp(DebuggerClient&);
    virtual void sendImpl(DebuggerThriftBuffer&);
    virtual void recvImpl(DebuggerThriftBuffer&);
  
    Type m_type;
    int m_version{0};
  
    std::string m_class; // for CmdExtended
    std::string m_body;
  
    // Used to save temporary error happened on the wire.
    std::string m_wireError;
  
    // Server side breaking out of message loop.
    bool m_exitInterrupt{false};
  
    // Another interrupt comes before the command could finish.
    bool m_incomplete{false};
  };
  
  ///////////////////////////////////////////////////////////////////////////////
  }}
  
  #endif // incl_HPHP_EVAL_DEBUGGER_COMMAND_H_
  