diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 316f009f19..7e69edcddb 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,34 @@ +Sun May 19 16:49:37 1996 Fred Fish + + * defs.h (read_command_lines, query_hook): Update prototypes. + (readline_begin_hook, readline_hook, readline_end_hook): Declare. + * breakpoint.c (commands_command): Build message in temporary buffer + and pass that, as well as tty control flag, to read_command_lines. + * top.c (readline_begin_hook, readline_hook, readline_end_hook): + Define here. + (command_loop): Check for non-NULL instream before looping. + (command_line_input): Use readline_hook when appropriate, to get + user input from a GUI window. + (read_next_line): Also build prompt if getting user input from a GUI. + (recurse_read_control_structure): Fix typo in comment. + (read_command_lines): Use passed in prompt and tty flag to decide how + to build message. Use readline_begin_hook when appropriate, to set + up a GUI interaction window. Just return head, whether NULL or not, + after using readline_end_hook to complete GUI interaction. + (define_command, document_command): Build message in a temporary + buffer and pass it to read_command_lines, along with tty flag. + +start-sanitize-gdbtk + * gdbtk.c (gdbtk_readline_begin, gdbtk_readline, gdbtk_readline_end): + New functions. + (tk_command_loop): Set instream to NULL to enable Tk user interaction. + (gdbtk_init): Set readline_begin_hook, readline_hook, + and readline_end_hook. + * gdbtk.tcl (gdbtk_tcl_readline_begin, gdbtk_tcl_readline, + gdbtk_tcl_readline_end): New functions. + (tclsh): Pack scroll bar on right side of window, not left. +end-sanitize-gdbtk + Sat May 18 02:43:58 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) * blockframe.c (frameless_look_for_prologue): diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 54c01b6b46..2356288136 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -330,10 +330,9 @@ commands_command (arg, from_tty) ALL_BREAKPOINTS (b) if (b->number == bnum) { - if (from_tty && input_from_terminal_p ()) - printf_filtered ("Type commands for when breakpoint %d is hit, one per line.\n\ -End with a line saying just \"end\".\n", bnum); - l = read_command_lines (); + char tmpbuf[128]; + sprintf (tmpbuf, "Type commands for when breakpoint %d is hit, one per line.", bnum); + l = read_command_lines (tmpbuf, from_tty); free_command_lines (&b->commands); b->commands = l; breakpoints_changed (); diff --git a/gdb/gdbtk.c b/gdb/gdbtk.c index 6234e4a012..2e244480c7 100644 --- a/gdb/gdbtk.c +++ b/gdb/gdbtk.c @@ -183,6 +183,64 @@ gdbtk_query (query, args) val = atol (interp->result); return val; } + +/* VARARGS */ +static void +#ifdef ANSI_PROTOTYPES +gdbtk_readline_begin (char *format, ...) +#else +gdbtk_readline_begin (va_alist) + va_dcl +#endif +{ + va_list args; + char buf[200], *merge[2]; + char *command; + +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + char *format; + va_start (args); + format = va_arg (args, char *); +#endif + + vsprintf (buf, format, args); + merge[0] = "gdbtk_tcl_readline_begin"; + merge[1] = buf; + command = Tcl_Merge (2, merge); + Tcl_Eval (interp, command); + free (command); +} + +static char * +gdbtk_readline (prompt) + char *prompt; +{ + char *merge[2]; + char *command; + + merge[0] = "gdbtk_tcl_readline"; + merge[1] = prompt; + command = Tcl_Merge (2, merge); + if (Tcl_Eval (interp, command) == TCL_OK) + { + return (strdup (interp -> result)); + } + else + { + gdbtk_fputs (interp -> result, gdb_stdout); + gdbtk_fputs ("\n", gdb_stdout); + return (NULL); + } +} + +static void +gdbtk_readline_end () +{ + Tcl_Eval (interp, "gdbtk_tcl_readline_end"); +} + static void #ifdef ANSI_PROTOTYPES @@ -1117,6 +1175,10 @@ gdbtk_call_command (cmdblk, arg, from_tty) static void tk_command_loop () { + extern GDB_FILE *instream; + + /* We no longer want to use stdin as the command input stream */ + instream = NULL; Tcl_Eval (interp, "gdbtk_tcl_preloop"); Tk_MainLoop (); } @@ -1180,6 +1242,9 @@ gdbtk_init () interactive_hook = gdbtk_interactive; target_wait_hook = gdbtk_wait; call_command_hook = gdbtk_call_command; + readline_begin_hook = gdbtk_readline_begin; + readline_hook = gdbtk_readline; + readline_end_hook = gdbtk_readline_end; /* Get the file descriptor for the X server */ diff --git a/gdb/gdbtk.tcl b/gdb/gdbtk.tcl index 30af7b3b5d..2bb5b27ffc 100644 --- a/gdb/gdbtk.tcl +++ b/gdb/gdbtk.tcl @@ -265,6 +265,86 @@ proc gdbtk_tcl_breakpoint {action bpnum} { ${action}_breakpoint $bpnum $file $line $pc } +# +# GDB Callback: +# +# gdbtk_tcl_readline_begin (message) - Notify Tk to open an interaction +# window and start gathering user input +# +# Description: +# +# GDB calls this to notify TK that it needs to open an interaction +# window, displaying the given message, and be prepared to accept +# calls to gdbtk_tcl_readline to gather user input. + +proc gdbtk_tcl_readline_begin {message} { + global readline_text + + # If another readline window already exists, just bring it to the front. + if {[winfo exists .rl]} {raise .rl ; return} + + # Create top level frame with scrollbar and text widget. + toplevel .rl + wm title .rl "Interaction Window" + wm iconname .rl "Input" + message .rl.msg -text $message -aspect 7500 -justify left + text .rl.text -width 80 -height 20 -setgrid true -cursor hand2 \ + -yscrollcommand {.rl.scroll set} + scrollbar .rl.scroll -command {.rl.text yview} + pack .rl.msg -side top -fill x + pack .rl.scroll -side right -fill y + pack .rl.text -side left -fill both -expand true + + # When the user presses return, get the text from the command start mark to the + # current insert point, stash it in the readline text variable, and update the + # command start mark to the current insert point + bind .rl.text { + set readline_text [.rl.text get cmdstart {end - 1 char}] + .rl.text mark set cmdstart insert + } + bindtags .rl.text {.rl.text Text all} +} + +# +# GDB Callback: +# +# gdbtk_tcl_readline (prompt) - Get one user input line +# +# Description: +# +# GDB calls this to get one line of input from the user interaction +# window, using "prompt" as the command line prompt. + +proc gdbtk_tcl_readline {prompt} { + global readline_text + + .rl.text insert end $prompt + .rl.text mark set cmdstart insert + .rl.text mark gravity cmdstart left + .rl.text see insert + + # Make this window the current one for input. + focus .rl.text + grab .rl + tkwait variable readline_text + grab release .rl + return $readline_text +} + +# +# GDB Callback: +# +# gdbtk_tcl_readline_end - Terminate a user interaction +# +# Description: +# +# GDB calls this when it is done getting interactive user input. +# Destroy the interaction window. + +proc gdbtk_tcl_readline_end {} { + if {[winfo exists .rl]} { destroy .rl } +} + proc create_breakpoints_window {} { global bpframe_lasty @@ -3149,8 +3229,8 @@ proc tclsh {} { text .eval.text -width 80 -height 20 -setgrid true -cursor hand2 \ -yscrollcommand {.eval.scroll set} scrollbar .eval.scroll -command {.eval.text yview} - pack .eval.scroll -side left -fill y - pack .eval.text -side right -fill both -expand true + pack .eval.scroll -side right -fill y + pack .eval.text -side left -fill both -expand true # Insert the tcl_prompt and initialize the cmdstart mark .eval.text insert insert $tcl_prompt diff --git a/gdb/top.c b/gdb/top.c index be7db39afc..bfab3f7306 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -275,7 +275,7 @@ struct cmd_list_element *showchecklist; /* stdio stream that command input is being read from. Set to stdin normally. Set by source_command to the file we are sourcing. Set to NULL if we are - executing a user-defined command. */ + executing a user-defined command or interacting via a GUI. */ FILE *instream; @@ -395,6 +395,21 @@ int (*query_hook) PARAMS (()); void (*flush_hook) PARAMS ((FILE *stream)); +/* These three functions support getting lines of text from the user. They + are used in sequence. First readline_begin_hook is called with a text + string that might be (for example) a message for the user to type in a + sequence of commands to be executed at a breakpoint. If this function + calls back to a GUI, it might take this opportunity to pop up a text + interaction window with this message. Next, readline_hook is called + with a prompt that is emitted prior to collecting the user input. + It can be called multiple times. Finally, readline_end_hook is called + to notify the GUI that we are done with the interaction window and it + can close it. */ + +void (*readline_begin_hook) PARAMS ((char *, ...)); +char * (*readline_hook) PARAMS ((char *)); +void (*readline_end_hook) PARAMS ((void)); + /* Called as appropriate to notify the interface of the specified breakpoint conditions. */ @@ -1237,7 +1252,7 @@ command_loop () extern int display_time; extern int display_space; - while (!feof (instream)) + while (instream && !feof (instream)) { if (window_hook && instream == stdin) (*window_hook) (instream, prompt); @@ -1962,11 +1977,18 @@ command_line_input (prrompt, repeat, annotation_suffix) } /* Don't use fancy stuff if not talking to stdin. */ - if (command_editing_p && instream == stdin - && ISATTY (instream)) - rl = readline (local_prompt); + if (readline_hook && instream == NULL) + { + rl = (*readline_hook) (local_prompt); + } + else if (command_editing_p && instream == stdin && ISATTY (instream)) + { + rl = readline (local_prompt); + } else - rl = gdb_readline (local_prompt); + { + rl = gdb_readline (local_prompt); + } if (annotation_level > 1 && instream == stdin) { @@ -2138,7 +2160,7 @@ read_next_line (command) error ("Control nesting too deep!\n"); /* Set a prompt based on the nesting of the control commands. */ - if (instream == stdin) + if (instream == stdin || (instream == 0 && readline_hook != NULL)) { for (i = 0; i < control_level; i++) control_prompt[i] = ' '; @@ -2220,7 +2242,7 @@ read_next_line (command) } /* Recursively read in the control structures and create a command_line - tructure from them. + structure from them. The parent_control parameter is the control structure in which the following commands are nested. */ @@ -2331,19 +2353,34 @@ recurse_read_control_structure (current_cmd) return ret; } +/* Read lines from the input stream and accumulate them in a chain of + struct command_line's, which is then returned. For input from a + terminal, the special command "end" is used to mark the end of the + input, and is not included in the returned chain of commands. */ -/* Read lines from the input stream - and accumulate them in a chain of struct command_line's - which is then returned. */ +#define END_MESSAGE "End with a line saying just \"end\"." struct command_line * -read_command_lines () +read_command_lines (prompt, from_tty) +char *prompt; +int from_tty; { struct command_line *head, *tail, *next; struct cleanup *old_chain; enum command_control_type ret; enum misc_command_type val; + if (readline_begin_hook) + { + /* Note - intentional to merge messages with no newline */ + (*readline_begin_hook) ("%s %s\n", prompt, END_MESSAGE); + } + else if (from_tty && input_from_terminal_p ()) + { + printf_unfiltered ("%s\n%s\n", prompt, END_MESSAGE); + gdb_flush (gdb_stdout); + } + head = tail = NULL; old_chain = NULL; @@ -2397,13 +2434,16 @@ read_command_lines () if (ret != invalid_control) { discard_cleanups (old_chain); - return head; } else do_cleanups (old_chain); } - return NULL; + if (readline_end_hook) + { + (*readline_end_hook) (); + } + return (head); } /* Free a chain of struct command_line's. */ @@ -2579,6 +2619,7 @@ define_command (comname, from_tty) register struct command_line *cmds; register struct cmd_list_element *c, *newc, *hookc = 0; char *tem = comname; + char tmpbuf[128]; #define HOOK_STRING "hook-" #define HOOK_LEN 5 @@ -2626,15 +2667,9 @@ define_command (comname, from_tty) for (tem = comname; *tem; tem++) if (isupper(*tem)) *tem = tolower(*tem); - if (from_tty) - { - printf_unfiltered ("Type commands for definition of \"%s\".\n\ -End with a line saying just \"end\".\n", comname); - gdb_flush (gdb_stdout); - } - control_level = 0; - cmds = read_command_lines (); + sprintf (tmpbuf, "Type commands for definition of \"%s\".", comname); + cmds = read_command_lines (tmpbuf, from_tty); if (c && c->class == class_user) free_command_lines (&c->user_commands); @@ -2661,6 +2696,7 @@ document_command (comname, from_tty) struct command_line *doclines; register struct cmd_list_element *c; char *tem = comname; + char tmpbuf[128]; validate_comname (comname); @@ -2669,11 +2705,8 @@ document_command (comname, from_tty) if (c->class != class_user) error ("Command \"%s\" is built-in.", comname); - if (from_tty) - printf_unfiltered ("Type documentation for \"%s\".\n\ -End with a line saying just \"end\".\n", comname); - - doclines = read_command_lines (); + sprintf (tmpbuf, "Type documentation for \"%s\".", comname); + doclines = read_command_lines (tmpbuf, from_tty); if (c->doc) free (c->doc);