1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef GUI_DEBUGGER_H 24 #define GUI_DEBUGGER_H 25 26 #include "common/func.h" 27 #include "common/ptr.h" 28 #include "common/hashmap.h" 29 #include "common/hash-str.h" 30 #include "common/array.h" 31 #include "common/str.h" 32 #include "common/str-array.h" 33 34 #include "engines/engine.h" 35 36 namespace GUI { 37 38 #ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER 39 class ConsoleDialog; 40 #endif 41 42 class Debugger { 43 public: 44 Debugger(); 45 virtual ~Debugger(); 46 47 int getCharsPerLine(); 48 49 int debugPrintf(const char *format, ...) GCC_PRINTF(2, 3); 50 51 void debugPrintColumns(const Common::StringArray &list); 52 53 /** 54 * The onFrame() method should be invoked by the engine at regular 55 * intervals (usually once per main loop iteration) whenever the 56 * debugger is attached. 57 * This will open up the console and accept user input if certain 58 * preconditions are met, such as the frame countdown having 59 * reached zero. 60 * 61 * Subclasses can override this to e.g. check for breakpoints being 62 * triggered. 63 */ 64 virtual void onFrame(); 65 66 /** 67 * 'Attach' the debugger. This ensures that the next time onFrame() 68 * is invoked, the debugger will activate and accept user input. 69 */ 70 virtual void attach(const char *entry = nullptr); 71 72 /** 73 * Return true if the debugger is currently active (i.e. executing 74 * a command or waiting for use input). 75 */ isActive()76 bool isActive() const { return _isActive; } 77 78 protected: 79 typedef Common::Functor2<int, const char **, bool> Debuglet; 80 81 /** 82 * Convenience macro that makes it easier to register a method 83 * of a debugger subclass as a command. 84 * Usage example: 85 * registerCmd("COMMAND", WRAP_METHOD(MyDebugger, myCmd)); 86 * would register the method MyDebugger::myCmd(int, const char **) 87 * under the command name "COMMAND". 88 */ 89 #define WRAP_METHOD(cls, method) \ 90 new Common::Functor2Mem<int, const char **, bool, cls>(this, &cls::method) 91 92 enum VarType { 93 DVAR_BYTE, 94 DVAR_INT, 95 DVAR_BOOL, 96 DVAR_INTARRAY, 97 DVAR_STRING 98 }; 99 100 struct Var { 101 Common::String name; 102 void *variable; 103 VarType type; 104 int arraySize; 105 }; 106 107 private: 108 /** 109 * Register a variable with the debugger. This allows the user to read and modify 110 * this variable. 111 * @param varname the identifier with which the user may access the variable 112 * @param variable pointer to the actual storage of the variable 113 * @param type the type of the variable (byte, int, bool, ...) 114 * @param arraySize for type DVAR_INTARRAY this specifies the size of the array 115 */ 116 void registerVarImpl(const Common::String &varname, void *variable, VarType type, int arraySize); 117 118 protected: registerVar(const Common::String & varname,byte * variable)119 void registerVar(const Common::String &varname, byte *variable) { 120 registerVarImpl(varname, variable, DVAR_BYTE, 0); 121 } 122 registerVar(const Common::String & varname,int * variable)123 void registerVar(const Common::String &varname, int *variable) { 124 registerVarImpl(varname, variable, DVAR_INT, 0); 125 } 126 registerVar(const Common::String & varname,bool * variable)127 void registerVar(const Common::String &varname, bool *variable) { 128 registerVarImpl(varname, variable, DVAR_BOOL, 0); 129 } 130 registerVar(const Common::String & varname,int32 ** variable,int arraySize)131 void registerVar(const Common::String &varname, int32 **variable, int arraySize) { 132 registerVarImpl(varname, variable, DVAR_INTARRAY, arraySize); 133 } 134 registerVar(const Common::String & varname,Common::String * variable)135 void registerVar(const Common::String &varname, Common::String *variable) { 136 registerVarImpl(varname, variable, DVAR_STRING, 0); 137 } 138 139 void registerCmd(const Common::String &cmdname, Debuglet *debuglet); 140 141 /** 142 * Remove all vars except default "debug_countdown" 143 */ 144 void clearVars(); 145 146 private: 147 /** 148 * The frame countdown specifies a number of frames that must pass 149 * until the console will show up. This value is decremented by one 150 * each time onFrame() is called, until it reaches 0, at which point 151 * onFrame() will open the console and handle input into it. 152 * 153 * The user can modify this value using the debug_countdown command. 154 * 155 * Note: The console must be in *attached* state, otherwise, it 156 * won't show up (and the countdown won't count down either). 157 */ 158 uint _frameCountdown; 159 160 Common::Array<Var> _vars; 161 162 typedef Common::HashMap<Common::String, Common::SharedPtr<Debuglet>, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> CommandsMap; 163 CommandsMap _cmds; 164 165 /** 166 * True if the debugger is currently active (i.e. executing 167 * a command or waiting for use input). 168 */ 169 bool _isActive; 170 171 Common::String _errStr; 172 173 /** 174 * Initially true, set to false when Debugger::enter is called 175 * the first time. We use this flag to show a greeting message 176 * to the user once, when he opens the debugger for the first 177 * time. 178 */ 179 bool _firstTime; 180 181 protected: 182 PauseToken _debugPauseToken; 183 184 #ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER 185 GUI::ConsoleDialog *_debuggerDialog; 186 #endif 187 188 protected: 189 /** 190 * Hook for subclasses which is called just before enter() is run. 191 * A typical usage example is pausing music and sound effects. 192 * 193 * The default implementation invokes Engine::pauseEngine(true). 194 */ 195 virtual void preEnter(); 196 197 /** 198 * Hook for subclasses which is called just after enter() was run. 199 * A typical usage example is resuming music and sound effects. 200 * 201 * The default implementation invokes Engine::pauseEngine(false). 202 */ 203 virtual void postEnter(); 204 205 /** 206 * Process the given command line. 207 * Returns true if and only if argv[0] is a known command and was 208 * handled, false otherwise. 209 */ 210 virtual bool handleCommand(int argc, const char **argv, bool &keepRunning); 211 212 /** 213 * Subclasses should invoke the detach() method in their cmdFOO methods 214 * if that command will resume execution of the program (as opposed to 215 * executing, say, a "single step through code" command). 216 * 217 * This currently only hides the virtual keyboard, if any. 218 */ 219 void detach(); 220 221 private: 222 void enter(); 223 224 /** 225 * Splits up the input into individual parameters 226 * @remarks Adapted from code provided by torek on StackOverflow 227 */ 228 void splitCommand(Common::String &input, int &argc, const char **argv); 229 230 bool parseCommand(const char *input); 231 bool tabComplete(const char *input, Common::String &completion) const; 232 233 protected: 234 bool cmdExit(int argc, const char **argv); 235 bool cmdHelp(int argc, const char **argv); 236 bool cmdOpenLog(int argc, const char **argv); 237 #ifndef DISABLE_MD5 238 bool cmdMd5(int argc, const char **argv); 239 bool cmdMd5Mac(int argc, const char **argv); 240 #endif 241 bool cmdDebugLevel(int argc, const char **argv); 242 bool cmdDebugFlagsList(int argc, const char **argv); 243 bool cmdDebugFlagEnable(int argc, const char **argv); 244 bool cmdDebugFlagDisable(int argc, const char **argv); 245 bool cmdExecFile(int argc, const char **argv); 246 247 #ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER 248 private: 249 static bool debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon); 250 static bool debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, Common::String &completion, void *refCon); 251 #elif defined(USE_READLINE) 252 public: 253 char *readlineComplete(const char *input, int state); 254 #endif 255 256 }; 257 258 } // End of namespace GUI 259 260 #endif 261