Add optional readline support to the text debugger console.

Make text/graphical console selectable with an option to configure.

svn-id: r42787
This commit is contained in:
Willem Jan Palenstijn 2009-07-25 23:36:24 +00:00
parent 037c02a1f7
commit 45cde5f642
3 changed files with 142 additions and 24 deletions

64
configure vendored
View file

@ -110,8 +110,10 @@ _alsa=auto
_zlib=auto _zlib=auto
_mpeg2=no _mpeg2=no
_fluidsynth=auto _fluidsynth=auto
_mt32emu=yes _readline=auto
# Default option behaviour yes/no # Default option behaviour yes/no
_text_console=no
_mt32emu=yes
_build_hq_scalers=yes _build_hq_scalers=yes
_build_scalers=yes _build_scalers=yes
# Default vkeybd/keymapper options # Default vkeybd/keymapper options
@ -580,6 +582,7 @@ $engines_help
--disable-mt32emu don't enable the integrated MT-32 emulator --disable-mt32emu don't enable the integrated MT-32 emulator
--disable-hq-scalers exclude HQ2x and HQ3x scalers --disable-hq-scalers exclude HQ2x and HQ3x scalers
--disable-scalers exclude scalers --disable-scalers exclude scalers
--enable-text-console use text console instead of graphical console
Optional Libraries: Optional Libraries:
--with-alsa-prefix=DIR Prefix where alsa is installed (optional) --with-alsa-prefix=DIR Prefix where alsa is installed (optional)
@ -612,6 +615,9 @@ Optional Libraries:
--with-nasm-prefix=DIR Prefix where nasm executable is installed (optional) --with-nasm-prefix=DIR Prefix where nasm executable is installed (optional)
--disable-nasm disable assembly language optimizations [autodetect] --disable-nasm disable assembly language optimizations [autodetect]
--with-readline-prefix=DIR Prefix where readline is installed (optional)
--disable-readline disable readline support in text console [autodetect]
Some influential environment variables: Some influential environment variables:
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir> nonstandard directory <lib dir>
@ -647,6 +653,8 @@ for ac_option in $@; do
--disable-nasm) _nasm=no ;; --disable-nasm) _nasm=no ;;
--enable-mpeg2) _mpeg2=yes ;; --enable-mpeg2) _mpeg2=yes ;;
--disable-fluidsynth) _fluidsynth=no ;; --disable-fluidsynth) _fluidsynth=no ;;
--enable-readline) _readline=yes ;;
--disable-readline) _readline=no ;;
--enable-plugins) _dynamic_modules=yes ;; --enable-plugins) _dynamic_modules=yes ;;
--default-dynamic) _plugins_default=dynamic ;; --default-dynamic) _plugins_default=dynamic ;;
--enable-mt32emu) _mt32emu=yes ;; --enable-mt32emu) _mt32emu=yes ;;
@ -655,6 +663,8 @@ for ac_option in $@; do
--disable-vkeybd) _vkeybd=no ;; --disable-vkeybd) _vkeybd=no ;;
--enable-keymapper) _keymapper=yes ;; --enable-keymapper) _keymapper=yes ;;
--disable-keymapper) _keymapper=no ;; --disable-keymapper) _keymapper=no ;;
--enable-text-console) _text_console=yes ;;
--disable-text-console) _text_console=no ;;
--with-fluidsynth-prefix=*) --with-fluidsynth-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2` arg=`echo $ac_option | cut -d '=' -f 2`
FLUIDSYNTH_CFLAGS="-I$arg/include" FLUIDSYNTH_CFLAGS="-I$arg/include"
@ -700,6 +710,11 @@ for ac_option in $@; do
ZLIB_CFLAGS="-I$arg/include" ZLIB_CFLAGS="-I$arg/include"
ZLIB_LIBS="-L$arg/lib" ZLIB_LIBS="-L$arg/lib"
;; ;;
--with-readline-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
READLINE_CFLAGS="-I$arg/include"
READLINE_LIBS="-L$arg/lib"
;;
--backend=*) --backend=*)
_backend=`echo $ac_option | cut -d '=' -f 2` _backend=`echo $ac_option | cut -d '=' -f 2`
;; ;;
@ -1801,6 +1816,45 @@ fi
echo "$_fluidsynth" echo "$_fluidsynth"
rm -rf $TMPC $TMPO$HOSTEXEEXT $TMPO.dSYM rm -rf $TMPC $TMPO$HOSTEXEEXT $TMPO.dSYM
#
# Check for readline if text_console is enabled
#
echocheck "readline"
if test "$_text_console" = yes ; then
if test "$_readline" = auto ; then
_readline=no
cat > $TMPC << EOF
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
int main(void) {
char *x = readline("");
}
EOF
cc_check $LDFLAGS $CXXFLAGS $READLINE_CFLAGS $READLINE_LIBS -lreadline && _readline=yes
fi
echo "$_readline"
rm -rf $TMPC $TMPO$HOSTEXEEXT $TMPO.dSYM
else
_readline=no
echo "skipping (text console disabled)"
fi
if test "$_readline" = yes ; then
_def_readline='#define USE_READLINE'
LIBS="$LIBS $READLINE_LIBS -lreadline"
INCLUDES="$INCLUDES $READLINE_CFLAGS"
else
_def_readline='#undef USE_READLINE'
fi
if test "$_text_console" = yes ; then
_def_text_console='#define USE_TEXT_CONSOLE'
else
_def_text_console='#undef USE_TEXT_CONSOLE'
fi
# #
# Check for nasm # Check for nasm
# #
@ -1884,6 +1938,10 @@ if test "$_mt32emu" = yes ; then
echo_n ", MT-32 emu" echo_n ", MT-32 emu"
fi fi
if test "$_text_console" = yes ; then
echo_n ", text console"
fi
if test "$_vkeybd" = yes ; then if test "$_vkeybd" = yes ; then
echo_n ", virtual keyboard" echo_n ", virtual keyboard"
fi fi
@ -2095,6 +2153,10 @@ $_def_alsa
$_def_zlib $_def_zlib
$_def_mpeg2 $_def_mpeg2
$_def_fluidsynth $_def_fluidsynth
$_def_readline
/* Options */
$_def_text_console
$_def_mt32emu $_def_mt32emu
/* Plugin settings */ /* Plugin settings */

View file

@ -27,10 +27,14 @@
#include "common/system.h" #include "common/system.h"
#include "gui/debugger.h" #include "gui/debugger.h"
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
#include "gui/console.h" #include "gui/console.h"
#elif defined(USE_READLINE)
#include <readline/readline.h>
#include <readline/history.h>
#endif #endif
namespace GUI { namespace GUI {
Debugger::Debugger() { Debugger::Debugger() {
@ -39,7 +43,7 @@ Debugger::Debugger() {
_isAttached = false; _isAttached = false;
_errStr = NULL; _errStr = NULL;
_firstTime = true; _firstTime = true;
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
_debuggerDialog = new GUI::ConsoleDialog(1.0f, 0.67f); _debuggerDialog = new GUI::ConsoleDialog(1.0f, 0.67f);
_debuggerDialog->setInputCallback(debuggerInputCallback, this); _debuggerDialog->setInputCallback(debuggerInputCallback, this);
_debuggerDialog->setCompletionCallback(debuggerCompletionCallback, this); _debuggerDialog->setCompletionCallback(debuggerCompletionCallback, this);
@ -57,7 +61,7 @@ Debugger::Debugger() {
} }
Debugger::~Debugger() { Debugger::~Debugger() {
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
delete _debuggerDialog; delete _debuggerDialog;
#endif #endif
} }
@ -69,7 +73,7 @@ int Debugger::DebugPrintf(const char *format, ...) {
va_start(argptr, format); va_start(argptr, format);
int count; int count;
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
count = _debuggerDialog->vprintf(format, argptr); count = _debuggerDialog->vprintf(format, argptr);
#else #else
count = ::vprintf(format, argptr); count = ::vprintf(format, argptr);
@ -116,9 +120,21 @@ void Debugger::onFrame() {
} }
} }
#if defined(USE_TEXT_CONSOLE) && defined(USE_READLINE)
static Debugger* g_readline_debugger;
char * readline_completionFunction (const char *text, int state)
{
return g_readline_debugger->readlineComplete(text, state);
}
#endif
// Main Debugger Loop // Main Debugger Loop
void Debugger::enter() { void Debugger::enter() {
#if USE_CONSOLE // TODO: Having three I/O methods #ifdef-ed in this file is not the
// cleanest approach to this...
#ifndef USE_TEXT_CONSOLE
if (_firstTime) { if (_firstTime) {
DebugPrintf("Debugger started, type 'exit' to return to the game.\n"); DebugPrintf("Debugger started, type 'exit' to return to the game.\n");
DebugPrintf("Type 'help' to see a little list of commands and variables.\n"); DebugPrintf("Type 'help' to see a little list of commands and variables.\n");
@ -133,18 +149,28 @@ void Debugger::enter() {
_debuggerDialog->runModal(); _debuggerDialog->runModal();
#else #else
// TODO: compared to the console input, this here is very bare bone.
// For example, no support for tab completion and no history. At least
// we should re-add (optional) support for the readline library.
// Or maybe instead of choosing between a console dialog and stdio,
// we should move that choice into the ConsoleDialog class - that is,
// the console dialog code could be #ifdef'ed to not print to the dialog
// but rather to stdio. This way, we could also reuse the command history
// and tab completion of the console. It would still require a lot of
// work, but at least no dependency on a 3rd party library...
printf("Debugger entered, please switch to this console for input.\n"); printf("Debugger entered, please switch to this console for input.\n");
#ifdef USE_READLINE
// TODO: add support for saving/loading history?
g_readline_debugger = this;
rl_completion_entry_function = &readline_completionFunction;
char *line_read = 0;
do {
free(line_read);
line_read = readline("debug> ");
if (line_read && line_read[0])
add_history(line_read);
} while (line_read && parseCommand(line_read));
free(line_read);
line_read = 0;
#else
int i; int i;
char buf[256]; char buf[256];
@ -160,6 +186,7 @@ void Debugger::enter() {
if (i == 0) if (i == 0)
continue; continue;
} while (parseCommand(buf)); } while (parseCommand(buf));
#endif
#endif #endif
} }
@ -330,6 +357,30 @@ bool Debugger::tabComplete(const char *input, Common::String &completion) const
return true; return true;
} }
#if defined(USE_TEXT_CONSOLE) && defined(USE_READLINE)
char* Debugger::readlineComplete(const char *input, int state)
{
static CommandsMap::const_iterator iter;
// We assume that _cmds isn't changed between calls to readlineComplete,
// unless state is 0.
if (state == 0) {
iter = _cmds.begin();
} else {
++iter;
}
for (; iter != _cmds.end(); ++iter) {
if (iter->_key.hasPrefix(input)) {
char *ret = (char *)malloc(iter->_key.size() + 1);
strcpy(ret, iter->_key.c_str());
return ret;
}
}
return 0;
}
#endif
// Variable registration function // Variable registration function
void Debugger::DVar_Register(const Common::String &varname, void *pointer, int type, int optional) { void Debugger::DVar_Register(const Common::String &varname, void *pointer, int type, int optional) {
// TODO: Filter out duplicates // TODO: Filter out duplicates
@ -361,9 +412,13 @@ bool Debugger::Cmd_Exit(int argc, const char **argv) {
// Print a list of all registered commands (and variables, if any), // Print a list of all registered commands (and variables, if any),
// nicely word-wrapped. // nicely word-wrapped.
bool Debugger::Cmd_Help(int argc, const char **argv) { bool Debugger::Cmd_Help(int argc, const char **argv) {
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
const int charsPerLine = _debuggerDialog->getCharsPerLine(); const int charsPerLine = _debuggerDialog->getCharsPerLine();
#elif defined(USE_READLINE)
int charsPerLine, rows;
rl_get_screen_size(&rows, &charsPerLine);
#else #else
// Can we do better?
const int charsPerLine = 80; const int charsPerLine = 80;
#endif #endif
int width, size; int width, size;
@ -460,7 +515,7 @@ bool Debugger::Cmd_DebugFlagDisable(int argc, const char **argv) {
} }
// Console handler // Console handler
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
bool Debugger::debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon) { bool Debugger::debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon) {
Debugger *debugger = (Debugger *)refCon; Debugger *debugger = (Debugger *)refCon;

View file

@ -32,10 +32,7 @@
namespace GUI { namespace GUI {
// Choose between text console or ScummConsole #ifndef USE_TEXT_CONSOLE
#define USE_CONSOLE 1
#if USE_CONSOLE
class ConsoleDialog; class ConsoleDialog;
#endif #endif
@ -86,7 +83,7 @@ private:
bool _isAttached; bool _isAttached;
char *_errStr; char *_errStr;
bool _firstTime; bool _firstTime;
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
GUI::ConsoleDialog *_debuggerDialog; GUI::ConsoleDialog *_debuggerDialog;
#endif #endif
@ -120,11 +117,15 @@ protected:
bool Cmd_DebugFlagEnable(int argc, const char **argv); bool Cmd_DebugFlagEnable(int argc, const char **argv);
bool Cmd_DebugFlagDisable(int argc, const char **argv); bool Cmd_DebugFlagDisable(int argc, const char **argv);
#if USE_CONSOLE #ifndef USE_TEXT_CONSOLE
private: private:
static bool debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon); static bool debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon);
static bool debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, Common::String &completion, void *refCon); static bool debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, Common::String &completion, void *refCon);
#elif defined(USE_READLINE)
public:
char* readlineComplete(const char *input, int state);
#endif #endif
}; };
} // End of namespace GUI } // End of namespace GUI