From 2e03ee74dfa6caf2953e73ff479d6e1461528f5f Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Wed, 3 Jan 2007 21:46:12 +0000 Subject: [PATCH] 2007-01-03 Jan Kratochvil Daniel Jacobowitz * Makefile.in (top.o): Update. * top.c (gdb_readline_wrapper_done, gdb_readline_wrapper_result) (saved_after_char_processing_hook, gdb_readline_wrapper_line) (struct gdb_readline_wrapper_cleanup, gdb_readline_wrapper_cleanup): New. (gdb_readline_wrapper): Rewrite to use asynchronous readline. 2007-01-03 Jan Kratochvil Daniel Jacobowitz * gdb.base/readline.exp: Set $TERM. Test arrow keys in secondary prompts. --- gdb/ChangeLog | 10 +++ gdb/Makefile.in | 2 +- gdb/testsuite/ChangeLog | 6 ++ gdb/testsuite/gdb.base/readline.exp | 22 +++++- gdb/top.c | 110 +++++++++++++++++++++++++--- 5 files changed, 136 insertions(+), 14 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7a1ad4cf64..9703777077 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2007-01-03 Jan Kratochvil + Daniel Jacobowitz + + * Makefile.in (top.o): Update. + * top.c (gdb_readline_wrapper_done, gdb_readline_wrapper_result) + (saved_after_char_processing_hook, gdb_readline_wrapper_line) + (struct gdb_readline_wrapper_cleanup, gdb_readline_wrapper_cleanup): + New. + (gdb_readline_wrapper): Rewrite to use asynchronous readline. + 2007-01-03 Mark Kettenis * arm-linux-tdep.c (arm_linux_extract_return_value): Remove. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 1b3e4730d5..46c1976bec 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2782,7 +2782,7 @@ top.o: top.c $(defs_h) $(gdbcmd_h) $(call_cmds_h) $(cli_cmds_h) \ $(annotate_h) $(completer_h) $(top_h) $(version_h) $(serial_h) \ $(doublest_h) $(gdb_assert_h) $(readline_h) $(readline_history_h) \ $(event_top_h) $(gdb_string_h) $(gdb_stat_h) $(ui_out_h) \ - $(cli_out_h) $(main_h) + $(cli_out_h) $(main_h) $(event_loop_h) tracepoint.o: tracepoint.c $(defs_h) $(symtab_h) $(frame_h) $(gdbtypes_h) \ $(expression_h) $(gdbcmd_h) $(value_h) $(target_h) $(language_h) \ $(gdb_string_h) $(inferior_h) $(tracepoint_h) $(remote_h) \ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 57f8aa6989..7ee795c3d5 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2007-01-03 Jan Kratochvil + Daniel Jacobowitz + + * gdb.base/readline.exp: Set $TERM. Test arrow keys in + secondary prompts. + 2007-01-03 Daniel Jacobowitz * gdb.cp/classes.exp (test_pointers_to_class_members): Update expected diff --git a/gdb/testsuite/gdb.base/readline.exp b/gdb/testsuite/gdb.base/readline.exp index 511cb6ba2e..2ad8580c84 100644 --- a/gdb/testsuite/gdb.base/readline.exp +++ b/gdb/testsuite/gdb.base/readline.exp @@ -1,4 +1,4 @@ -# Copyright 2002 Free Software Foundation, Inc. +# Copyright 2002, 2003, 2007 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -159,6 +159,14 @@ if [info exists env(INPUTRC)] { } set env(INPUTRC) "/dev/null" +# The arrow key test relies on the standard VT100 bindings, so make +# sure that an appropriate terminal is selected. The same bug +# doesn't show up if we use ^P / ^N instead. +if [info exists env(TERM)] { + set old_term $env(TERM) +} +set env(TERM) "vt100" + gdb_start gdb_reinitialize_dir $srcdir/$subdir @@ -178,6 +186,18 @@ operate_and_get_next "operate-and-get-next with secondary prompt" \ "p 5" "" \ "end" ".* = 5" +# Verify that arrow keys work in secondary prompts. The control +# sequence is a hard-coded VT100 up arrow. +gdb_test "print 42" "\\\$\[0-9\]* = 42" +set msg "arrow keys with secondary prompt" +gdb_test_multiple "if 1 > 0\n\033\[A\033\[A\nend" $msg { + -re ".*\\\$\[0-9\]* = 42\r\n$gdb_prompt $" { + pass $msg + } + -re ".*Undefined command:.*$gdb_prompt $" { + fail $msg + } +} # Now repeat the first test with a history file that fills the entire # history list. diff --git a/gdb/top.c b/gdb/top.c index 14eb087d39..b4790393f9 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -47,6 +47,7 @@ #include "doublest.h" #include "gdb_assert.h" #include "main.h" +#include "event-loop.h" /* readline include files */ #include "readline/readline.h" @@ -712,26 +713,111 @@ The filename in which to record the command history is \"%s\".\n"), } /* This is like readline(), but it has some gdb-specific behavior. - gdb can use readline in both the synchronous and async modes during + gdb may want readline in both the synchronous and async modes during a single gdb invocation. At the ordinary top-level prompt we might be using the async readline. That means we can't use rl_pre_input_hook, since it doesn't work properly in async mode. However, for a secondary prompt (" >", such as occurs during a - `define'), gdb just calls readline() directly, running it in - synchronous mode. So for operate-and-get-next to work in this - situation, we have to switch the hooks around. That is what - gdb_readline_wrapper is for. */ + `define'), gdb wants a synchronous response. + + We used to call readline() directly, running it in synchronous + mode. But mixing modes this way is not supported, and as of + readline 5.x it no longer works; the arrow keys come unbound during + the synchronous call. So we make a nested call into the event + loop. That's what gdb_readline_wrapper is for. */ + +/* A flag set as soon as gdb_readline_wrapper_line is called; we can't + rely on gdb_readline_wrapper_result, which might still be NULL if + the user types Control-D for EOF. */ +static int gdb_readline_wrapper_done; + +/* The result of the current call to gdb_readline_wrapper, once a newline + is seen. */ +static char *gdb_readline_wrapper_result; + +/* Any intercepted hook. Operate-and-get-next sets this, expecting it + to be called after the newline is processed (which will redisplay + the prompt). But in gdb_readline_wrapper we will not get a new + prompt until the next call, or until we return to the event loop. + So we disable this hook around the newline and restore it before we + return. */ +static void (*saved_after_char_processing_hook) (void); + +/* This function is called when readline has seen a complete line of + text. */ + +static void +gdb_readline_wrapper_line (char *line) +{ + gdb_assert (!gdb_readline_wrapper_done); + gdb_readline_wrapper_result = line; + gdb_readline_wrapper_done = 1; + + /* Prevent operate-and-get-next from acting too early. */ + saved_after_char_processing_hook = after_char_processing_hook; + after_char_processing_hook = NULL; +} + +struct gdb_readline_wrapper_cleanup + { + void (*handler_orig) (char *); + char *prompt_orig; + int already_prompted_orig; + }; + +static void +gdb_readline_wrapper_cleanup (void *arg) +{ + struct gdb_readline_wrapper_cleanup *cleanup = arg; + + gdb_assert (rl_already_prompted == 1); + rl_already_prompted = cleanup->already_prompted_orig; + PROMPT (0) = cleanup->prompt_orig; + + gdb_assert (input_handler == gdb_readline_wrapper_line); + input_handler = cleanup->handler_orig; + gdb_readline_wrapper_result = NULL; + gdb_readline_wrapper_done = 0; + + after_char_processing_hook = saved_after_char_processing_hook; + saved_after_char_processing_hook = NULL; + + xfree (cleanup); +} + char * gdb_readline_wrapper (char *prompt) { - /* Set the hook that works in this case. */ - if (after_char_processing_hook) - { - rl_pre_input_hook = (Function *) after_char_processing_hook; - after_char_processing_hook = NULL; - } + struct cleanup *back_to; + struct gdb_readline_wrapper_cleanup *cleanup; + char *retval; - return readline (prompt); + cleanup = xmalloc (sizeof (*cleanup)); + cleanup->handler_orig = input_handler; + input_handler = gdb_readline_wrapper_line; + + cleanup->prompt_orig = get_prompt (); + PROMPT (0) = prompt; + cleanup->already_prompted_orig = rl_already_prompted; + + back_to = make_cleanup (gdb_readline_wrapper_cleanup, cleanup); + + /* Display our prompt and prevent double prompt display. */ + display_gdb_prompt (NULL); + rl_already_prompted = 1; + + if (after_char_processing_hook) + (*after_char_processing_hook) (); + gdb_assert (after_char_processing_hook == NULL); + + /* gdb_do_one_event argument is unused. */ + while (gdb_do_one_event (NULL) >= 0) + if (gdb_readline_wrapper_done) + break; + + retval = gdb_readline_wrapper_result; + do_cleanups (back_to); + return retval; }