]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/tui/tui.c
GDB copyright headers update after running GDB's copyright.py script.
[thirdparty/binutils-gdb.git] / gdb / tui / tui.c
index 53b8452df6903a4b8e4b5825de3647222cffc919..273a0d9d8ba49d9ef8a39f418e75fe9146811eb7 100644 (file)
-/*
-   ** tui.c
-   **         General functions for the WDB TUI
- */
+/* General functions for the WDB TUI.
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <malloc.h>
-#include <curses.h>
-#ifdef HAVE_TERM_H
-#include <term.h>
-#endif
-#include <signal.h>
-#include <fcntl.h>
-#include <termio.h>
-#include <setjmp.h>
-#include "defs.h"
-#include "gdbcmd.h"
-#include "tui.h"
-#include "tuiData.h"
-#include "tuiLayout.h"
-#include "tuiIO.h"
-#include "tuiRegs.h"
-#include "tuiWin.h"
-
-/* The Solaris header files seem to provide no declaration for this at
-   all when __STDC__ is defined.  This shouldn't conflict with
-   anything.  */
-extern char *tgoto ();
-
-/***********************
-** Local Definitions
-************************/
-#define FILEDES         2
-/* Solaris <sys/termios.h> defines CTRL. */
-#ifndef CTRL
-#define CTRL(x)         (x & ~0140)
-#endif
-#define CHK(val, dft)   (val<=0 ? dft : val)
-
-#define TOGGLE_USAGE "Usage:toggle breakpoints"
-#define TUI_TOGGLE_USAGE "Usage:\ttoggle $fregs\n\ttoggle breakpoints"
+   Copyright (C) 1998-2016 Free Software Foundation, Inc.
 
-/*****************************
-** Local static forward decls
-******************************/
-static void _tuiReset PARAMS ((void));
-static void _toggle_command PARAMS ((char *, int));
-static void _tui_vToggle_command PARAMS ((va_list));
-static Opaque _tui_vDo PARAMS ((TuiOpaqueFuncPtr, va_list));
+   Contributed by Hewlett-Packard Company.
 
+   This file is part of GDB.
 
+   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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
-/***********************
-** Public Functions
-************************/
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-/*
-   ** tuiInit().
- */
-void
-#ifdef __STDC__
-tuiInit (char *argv0)
-#else
-tuiInit (argv0)
-     char *argv0;
-#endif
-{
-  extern void init_page_info ();
-  extern void initialize_tui_files PARAMS ((void));
-
-  initialize_tui_files ();
-  initializeStaticData ();
-  initscr ();
-  refresh ();
-  setTermHeightTo (LINES);
-  setTermWidthTo (COLS);
-  tuiInitWindows ();
-  wrefresh (cmdWin->generic.handle);
-  init_page_info ();
-  /* Don't hook debugger output if doing command-window
-     * the XDB way. However, one thing we do want to do in
-     * XDB style is set up the scrolling region to be
-     * the bottom of the screen (tuiTermUnsetup()).
-   */
-  fputs_unfiltered_hook = NULL;
-  flush_hook = NULL;
-  rl_initialize ();            /* need readline initialization to
-                                  * create termcap sequences
-                                */
-  tuiTermUnsetup (1, cmdWin->detail.commandInfo.curch);
-
-  return;
-}                              /* tuiInit */
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+#include "defs.h"
+#include "gdbcmd.h"
+#include "tui/tui.h"
+#include "tui/tui-hooks.h"
+#include "tui/tui-data.h"
+#include "tui/tui-layout.h"
+#include "tui/tui-io.h"
+#include "tui/tui-regs.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-win.h"
+#include "tui/tui-winsource.h"
+#include "tui/tui-windata.h"
+#include "target.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "source.h"
+#include "terminal.h"
 
-/*
-   ** tuiInitWindows().
- */
-void
-#ifdef __STDC__
-tuiInitWindows (void)
-#else
-tuiInitWindows ()
+#include <ctype.h>
+#include <signal.h>
+#include <fcntl.h>
+#if 0
+#include <termio.h>
 #endif
-{
-  TuiWinType type;
+#include <setjmp.h>
 
-  tuiSetLocatorContent (0);
-  showLayout (SRC_COMMAND);
-  keypad (cmdWin->generic.handle, TRUE);
-  echo ();
-  crmode ();
-  nl ();
-  tuiSetWinFocusTo (srcWin);
+#include "gdb_curses.h"
+#include "interps.h"
 
-  return;
-}                              /* tuiInitWindows */
+/* This redefines CTRL if it is not already defined, so it must come
+   after terminal state releated include files like <term.h> and
+   "gdb_curses.h".  */
+#include "readline/readline.h"
 
+/* Tells whether the TUI is active or not.  */
+int tui_active = 0;
+static int tui_finish_init = 1;
 
-/*
-   ** tuiCleanUp().
-   **        Kill signal handler and cleanup termination method
- */
-void
-#ifdef __STDC__
-tuiResetScreen (void)
-#else
-tuiResetScreen ()
-#endif
+enum tui_key_mode tui_current_key_mode = TUI_COMMAND_MODE;
+
+struct tui_char_command
+{
+  unsigned char key;
+  const char *cmd;
+};
+
+/* Key mapping to gdb commands when the TUI is using the single key
+   mode.  */
+static const struct tui_char_command tui_commands[] = {
+  { 'c', "continue" },
+  { 'd', "down" },
+  { 'f', "finish" },
+  { 'n', "next" },
+  { 'r', "run" },
+  { 's', "step" },
+  { 'u', "up" },
+  { 'v', "info locals" },
+  { 'w', "where" },
+  { 0, 0 },
+};
+
+static Keymap tui_keymap;
+static Keymap tui_readline_standard_keymap;
+
+/* TUI readline command.
+   Switch the output mode between TUI/standard gdb.  */
+static int
+tui_rl_switch_mode (int notused1, int notused2)
 {
-  TuiWinType type = SRC_WIN;
 
-  keypad (cmdWin->generic.handle, FALSE);
-  for (; type < MAX_MAJOR_WINDOWS; type++)
+  /* Don't let exceptions escape.  We're in the middle of a readline
+     callback that isn't prepared for that.  */
+  TRY
     {
-      if (m_winPtrNotNull (winList[type]) &&
-         winList[type]->generic.type != UNDEFINED_WIN &&
-         !winList[type]->generic.isVisible)
-       tuiDelWindow (winList[type]);
+      if (tui_active)
+       {
+         tui_disable ();
+         rl_prep_terminal (0);
+       }
+      else
+       {
+         /* If tui_enable throws, we'll re-prep below.  */
+         rl_deprep_terminal ();
+         tui_enable ();
+       }
     }
-  endwin ();
-  initscr ();
-  refresh ();
-  echo ();
-  crmode ();
-  nl ();
-
-  return;
-}                              /* tuiResetScreen */
+  CATCH (ex, RETURN_MASK_ALL)
+    {
+      exception_print (gdb_stderr, ex);
 
+      if (!tui_active)
+       rl_prep_terminal (0);
+    }
+  END_CATCH
+
+  /* Clear the readline in case switching occurred in middle of
+     something.  */
+  if (rl_end)
+    rl_kill_text (0, rl_end);
+
+  /* Since we left the curses mode, the terminal mode is restored to
+     some previous state.  That state may not be suitable for readline
+     to work correctly (it may be restored in line mode).  We force an
+     exit of the current readline so that readline is re-entered and
+     it will be able to setup the terminal for its needs.  By
+     re-entering in readline, we also redisplay its prompt in the
+     non-curses mode.  */
+  rl_newline (1, '\n');
+
+  /* Make sure the \n we are returning does not repeat the last
+     command.  */
+  dont_repeat ();
+  return 0;
+}
 
-/*
-   ** tuiCleanUp().
-   **        Kill signal handler and cleanup termination method
- */
-void
-#ifdef __STDC__
-tuiCleanUp (void)
-#else
-tuiCleanUp ()
-#endif
+/* TUI readline command.
+   Change the TUI layout to show a next layout.
+   This function is bound to CTRL-X 2.  It is intended to provide
+   a functionality close to the Emacs split-window command.  We
+   always show two windows (src+asm), (src+regs) or (asm+regs).  */
+static int
+tui_rl_change_windows (int notused1, int notused2)
 {
-  char *buffer;
-  extern char *term_cursor_move;
+  if (!tui_active)
+    tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
 
-  signal (SIGINT, SIG_IGN);
-  tuiTermSetup (0);            /* Restore scrolling region to whole screen */
-  keypad (cmdWin->generic.handle, FALSE);
-  freeAllWindows ();
-  endwin ();
-  buffer = tgoto (term_cursor_move, 0, termHeight ());
-  tputs (buffer, 1, putchar);
-  _tuiReset ();
-
-  return;
-}                              /* tuiCleanUp */
-
-
-/*
-   ** tuiError().
- */
-void
-#ifdef __STDC__
-tuiError (
-          char *string,
-          int exitGdb)
-#else
-tuiError (string, exitGdb)
-     char *string;
-     int exitGdb;
-#endif
-{
-  puts_unfiltered (string);
-  if (exitGdb)
+  if (tui_active)
     {
-      tuiCleanUp ();
-      exit (-1);
+      enum tui_layout_type new_layout;
+
+      new_layout = tui_current_layout ();
+
+      /* Select a new layout to have a rolling layout behavior with
+        always two windows (except when undefined).  */
+      switch (new_layout)
+       {
+       case SRC_COMMAND:
+         new_layout = SRC_DISASSEM_COMMAND;
+         break;
+
+       case DISASSEM_COMMAND:
+         new_layout = SRC_DISASSEM_COMMAND;
+         break;
+
+       case SRC_DATA_COMMAND:
+         new_layout = SRC_DISASSEM_COMMAND;
+         break;
+
+       case SRC_DISASSEM_COMMAND:
+         new_layout = DISASSEM_DATA_COMMAND;
+         break;
+         
+       case DISASSEM_DATA_COMMAND:
+         new_layout = SRC_DATA_COMMAND;
+         break;
+
+       default:
+         new_layout = SRC_COMMAND;
+         break;
+       }
+      tui_set_layout (new_layout);
     }
+  return 0;
+}
 
-  return;
-}                              /* tuiError */
-
-
-/*
-   ** tui_vError()
-   **        tuiError with args in a va_list.
- */
-void
-#ifdef __STDC__
-tui_vError (
-            va_list args)
-#else
-tui_vError (args)
-     va_list args;
-#endif
+/* TUI readline command.
+   Delete the second TUI window to only show one.  */
+static int
+tui_rl_delete_other_windows (int notused1, int notused2)
 {
-  char *string;
-  int exitGdb;
-
-  string = va_arg (args, char *);
-  exitGdb = va_arg (args, int);
+  if (!tui_active)
+    tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
 
-  tuiError (string, exitGdb);
+  if (tui_active)
+    {
+      enum tui_layout_type new_layout;
+
+      new_layout = tui_current_layout ();
+
+      /* Kill one window.  */
+      switch (new_layout)
+       {
+       case SRC_COMMAND:
+       case SRC_DATA_COMMAND:
+       case SRC_DISASSEM_COMMAND:
+       default:
+         new_layout = SRC_COMMAND;
+         break;
+
+       case DISASSEM_COMMAND:
+       case DISASSEM_DATA_COMMAND:
+         new_layout = DISASSEM_COMMAND;
+         break;
+       }
+      tui_set_layout (new_layout);
+    }
+  return 0;
+}
 
-  return;
-}                              /* tui_vError */
+/* TUI readline command.
+   Switch the active window to give the focus to a next window.  */
+static int
+tui_rl_other_window (int count, int key)
+{
+  struct tui_win_info *win_info;
 
+  if (!tui_active)
+    tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
 
-/*
-   ** tuiFree()
-   **    Wrapper on top of free() to ensure that input address is greater than 0x0
- */
-void
-#ifdef __STDC__
-tuiFree (
-         char *ptr)
-#else
-tuiFree (ptr)
-     char *ptr;
-#endif
-{
-  if (ptr != (char *) NULL)
+  win_info = tui_next_win (tui_win_with_focus ());
+  if (win_info)
     {
-      free (ptr);
+      tui_set_win_focus_to (win_info);
+      if (TUI_DATA_WIN && TUI_DATA_WIN->generic.is_visible)
+        tui_refresh_data_win ();
+      keypad (TUI_CMD_WIN->generic.handle, (win_info != TUI_CMD_WIN));
     }
+  return 0;
+}
 
-  return;
-}                              /* tuiFree */
-
-
-/* tuiGetLowDisassemblyAddress().
-   **        Determine what the low address will be to display in the TUI's
-   **        disassembly window.  This may or may not be the same as the
-   **        low address input.
- */
-Opaque
-#ifdef __STDC__
-tuiGetLowDisassemblyAddress (
-                             Opaque low,
-                             Opaque pc)
-#else
-tuiGetLowDisassemblyAddress (low, pc)
-     Opaque low;
-     Opaque pc;
-#endif
+/* TUI readline command.
+   Execute the gdb command bound to the specified key.  */
+static int
+tui_rl_command_key (int count, int key)
 {
-  int line;
-  Opaque newLow;
-
-  /*
-     ** Determine where to start the disassembly so that the pc is about in the
-     ** middle of the viewport.
-   */
-  for (line = 0, newLow = pc;
-       (newLow > low &&
-       line < (tuiDefaultWinViewportHeight (DISASSEM_WIN,
-                                            DISASSEM_COMMAND) / 2));)
-    {
-      bfd_byte buffer[4];
+  int i;
 
-      newLow -= sizeof (bfd_getb32 (buffer));
-      line++;
+  reinitialize_more_filter ();
+  for (i = 0; tui_commands[i].cmd; i++)
+    {
+      if (tui_commands[i].key == key)
+        {
+          /* Insert the command in the readline buffer.
+             Avoid calling the gdb command here since it creates
+             a possible recursion on readline if prompt_for_continue
+             is called (See PR 9584).  The command will also appear
+             in the readline history which turns out to be better.  */
+          rl_insert_text (tui_commands[i].cmd);
+          rl_newline (1, '\n');
+
+          /* Switch to gdb command mode while executing the command.
+             This way the gdb's continue prompty will be displayed.  */
+          tui_set_key_mode (TUI_ONE_COMMAND_MODE);
+          return 0;
+        }
     }
+  return 0;
+}
 
-  return newLow;
-}                              /* tuiGetLowDisassemblyAddress */
-
-
-/* tui_vGetLowDisassemblyAddress().
-   **        Determine what the low address will be to display in the TUI's
-   **        disassembly window with args in a va_list.
- */
-Opaque
-#ifdef __STDC__
-tui_vGetLowDisassemblyAddress (
-                               va_list args)
-#else
-tui_vGetLowDisassemblyAddress (args)
-     va_list args;
-#endif
-{
-  int line;
-  Opaque newLow;
-  Opaque low;
-  Opaque pc;
-
-  low = va_arg (args, Opaque);
-  pc = va_arg (args, Opaque);
-
-  return (tuiGetLowDisassemblyAddress (low, pc));
-
-}                              /* tui_vGetLowDisassemblyAddress */
-
-
-/*
-   ** tuiDo().
-   **        General purpose function to execute a tui function.  Transitions
-   **        between curses and the are handled here.  This function is called
-   **        by non-tui gdb functions.
-   **
-   **        Errors are caught here.
-   **        If there is no error, the value returned by 'func' is returned.
-   **        If there is an error, then zero is returned.
-   **
-   **       Must not be called with immediate_quit in effect (bad things might
-   **       happen, say we got a signal in the middle of a memcpy to quit_return).
-   **       This is an OK restriction; with very few exceptions immediate_quit can
-   **       be replaced by judicious use of QUIT.
- */
-Opaque
-#ifdef __STDC__
-tuiDo (
-       TuiOpaqueFuncPtr func,...)
-#else
-tuiDo (func, va_alist)
-     TuiOpaqueFuncPtr func;
-     va_dcl
-#endif
+/* TUI readline command.
+   Temporarily leave the TUI SingleKey mode to allow editing
+   a gdb command with the normal readline.  Once the command
+   is executed, the TUI SingleKey mode is installed back.  */
+static int
+tui_rl_command_mode (int count, int key)
 {
-  extern int terminal_is_ours;
+  tui_set_key_mode (TUI_ONE_COMMAND_MODE);
+  return rl_insert (count, key);
+}
 
-  Opaque ret = (Opaque) NULL;
+/* TUI readline command.
+   Switch between TUI SingleKey mode and gdb readline editing.  */
+static int
+tui_rl_next_keymap (int notused1, int notused2)
+{
+  if (!tui_active)
+    tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
 
-  /* It is an error to be tuiDo'ing if we
-     * don't own the terminal.
-   */
-  if (!terminal_is_ours)
-    return ret;
+  tui_set_key_mode (tui_current_key_mode == TUI_COMMAND_MODE
+                    ? TUI_SINGLE_KEY_MODE : TUI_COMMAND_MODE);
+  return 0;
+}
 
-  if (tui_version)
-    {
-      va_list args;
+/* Readline hook to redisplay ourself the gdb prompt.
+   In the SingleKey mode, the prompt is not printed so that
+   the command window is cleaner.  It will be displayed if
+   we temporarily leave the SingleKey mode.  */
+static int
+tui_rl_startup_hook (void)
+{
+  rl_already_prompted = 1;
+  if (tui_current_key_mode != TUI_COMMAND_MODE && immediate_quit == 0)
+    tui_set_key_mode (TUI_SINGLE_KEY_MODE);
+  tui_redisplay_readline ();
+  return 0;
+}
 
-#ifdef __STDC__
-      va_start (args, func);
-#else
-      va_start (args);
-#endif
-      ret = _tui_vDo (func, args);
-      va_end (args);
-    }
+/* Change the TUI key mode by installing the appropriate readline
+   keymap.  */
+void
+tui_set_key_mode (enum tui_key_mode mode)
+{
+  tui_current_key_mode = mode;
+  rl_set_keymap (mode == TUI_SINGLE_KEY_MODE
+                 ? tui_keymap : tui_readline_standard_keymap);
+  tui_show_locator_content ();
+}
 
-  return ret;
-}                              /* tuiDo */
-
-
-/*
-   ** tuiDoAndReturnToTop().
-   **        General purpose function to execute a tui function.  Transitions
-   **        between curses and the are handled here.  This function is called
-   **        by non-tui gdb functions who wish to reset gdb to the top level.
-   **        After the tuiDo is performed, a return to the top level occurs.
-   **
-   **        Errors are caught here.
-   **        If there is no error, the value returned by 'func' is returned.
-   **        If there is an error, then zero is returned.
-   **
-   **       Must not be called with immediate_quit in effect (bad things might
-   **       happen, say we got a signal in the middle of a memcpy to quit_return).
-   **       This is an OK restriction; with very few exceptions immediate_quit can
-   **       be replaced by judicious use of QUIT.
-   **
- */
-Opaque
-#ifdef __STDC__
-tuiDoAndReturnToTop (
-                     TuiOpaqueFuncPtr func,...)
-#else
-tuiDoAndReturnToTop (func, va_alist)
-     TuiOpaqueFuncPtr func;
-     va_dcl
-#endif
+/* Initialize readline and configure the keymap for the switching
+   key shortcut.  */
+void
+tui_initialize_readline (void)
 {
-  extern int terminal_is_ours;
+  int i;
+  Keymap tui_ctlx_keymap;
+
+  rl_initialize ();
+
+  rl_add_defun ("tui-switch-mode", tui_rl_switch_mode, -1);
+  rl_add_defun ("gdb-command", tui_rl_command_key, -1);
+  rl_add_defun ("next-keymap", tui_rl_next_keymap, -1);
+
+  tui_keymap = rl_make_bare_keymap ();
+  tui_ctlx_keymap = rl_make_bare_keymap ();
+  tui_readline_standard_keymap = rl_get_keymap ();
 
-  Opaque ret = (Opaque) NULL;
+  for (i = 0; tui_commands[i].cmd; i++)
+    rl_bind_key_in_map (tui_commands[i].key, tui_rl_command_key, tui_keymap);
 
-  /* It is an error to be tuiDo'ing if we
-     * don't own the terminal.
-   */
-  if (!terminal_is_ours)
-    return ret;
+  rl_generic_bind (ISKMAP, "\\C-x", (char*) tui_ctlx_keymap, tui_keymap);
 
-  if (tui_version)
+  /* Bind all other keys to tui_rl_command_mode so that we switch
+     temporarily from SingleKey mode and can enter a gdb command.  */
+  for (i = ' '; i < 0x7f; i++)
     {
-      va_list args;
+      int j;
 
-#ifdef __STDC__
-      va_start (args, func);
-#else
-      va_start (args);
-#endif
-      ret = _tui_vDo (func, args);
+      for (j = 0; tui_commands[j].cmd; j++)
+        if (tui_commands[j].key == i)
+          break;
+
+      if (tui_commands[j].cmd)
+        continue;
 
-      /* force a return to the top level */
-      return_to_top_level (RETURN_ERROR);
+      rl_bind_key_in_map (i, tui_rl_command_mode, tui_keymap);
     }
 
-  return ret;
-}                              /* tuiDoAndReturnToTop */
+  rl_bind_key_in_map ('a', tui_rl_switch_mode, emacs_ctlx_keymap);
+  rl_bind_key_in_map ('a', tui_rl_switch_mode, tui_ctlx_keymap);
+  rl_bind_key_in_map ('A', tui_rl_switch_mode, emacs_ctlx_keymap);
+  rl_bind_key_in_map ('A', tui_rl_switch_mode, tui_ctlx_keymap);
+  rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, emacs_ctlx_keymap);
+  rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, tui_ctlx_keymap);
+  rl_bind_key_in_map ('1', tui_rl_delete_other_windows, emacs_ctlx_keymap);
+  rl_bind_key_in_map ('1', tui_rl_delete_other_windows, tui_ctlx_keymap);
+  rl_bind_key_in_map ('2', tui_rl_change_windows, emacs_ctlx_keymap);
+  rl_bind_key_in_map ('2', tui_rl_change_windows, tui_ctlx_keymap);
+  rl_bind_key_in_map ('o', tui_rl_other_window, emacs_ctlx_keymap);
+  rl_bind_key_in_map ('o', tui_rl_other_window, tui_ctlx_keymap);
+  rl_bind_key_in_map ('q', tui_rl_next_keymap, tui_keymap);
+  rl_bind_key_in_map ('s', tui_rl_next_keymap, emacs_ctlx_keymap);
+  rl_bind_key_in_map ('s', tui_rl_next_keymap, tui_ctlx_keymap);
+}
 
+/* Return the TERM variable from the environment, or "<unset>"
+   if not set.  */
 
-void
-#ifdef __STDC__
-tui_vSelectSourceSymtab (
-                         va_list args)
-#else
-tui_vSelectSourceSymtab (args)
-     va_list args;
-#endif
+static const char *
+gdb_getenv_term (void)
 {
-  struct symtab *s = va_arg (args, struct symtab *);
-
-  select_source_symtab (s);
-  return;
-}                              /* tui_vSelectSourceSymtab */
+  const char *term;
 
+  term = getenv ("TERM");
+  if (term != NULL)
+    return term;
+  return "<unset>";
+}
 
-/*
-   ** _initialize_tui().
-   **      Function to initialize gdb commands, for tui window manipulation.
- */
+/* Enter in the tui mode (curses).
+   When in normal mode, it installs the tui hooks in gdb, redirects
+   the gdb output, configures the readline to work in tui mode.
  When in curses mode, it does nothing.  */
 void
-_initialize_tui ()
+tui_enable (void)
 {
-#if 0
-  if (tui_version)
+  struct interp *interp;
+
+  if (tui_active)
+    return;
+
+  /* To avoid to initialize curses when gdb starts, there is a defered
+     curses initialization.  This initialization is made only once
+     and the first time the curses mode is entered.  */
+  if (tui_finish_init)
     {
-      add_com ("toggle", class_tui, _toggle_command,
-              "Toggle Terminal UI Features\n\
-Usage: Toggle $fregs\n\
-\tToggles between single and double precision floating point registers.\n");
-    }
+      WINDOW *w;
+      SCREEN *s;
+      const char *cap;
+      const char *interp;
+
+      /* If the top level interpreter is not the console/tui (e.g.,
+        MI), enabling curses will certainly lose.  */
+      interp = interp_name (top_level_interpreter ());
+      if (strcmp (interp, INTERP_TUI) != 0)
+       error (_("Cannot enable the TUI when the interpreter is '%s'"), interp);
+
+      /* Don't try to setup curses (and print funny control
+        characters) if we're not outputting to a terminal.  */
+      if (!ui_file_isatty (gdb_stdout))
+       error (_("Cannot enable the TUI when output is not a terminal"));
+
+      s = newterm (NULL, stdout, stdin);
+#ifdef __MINGW32__
+      /* The MinGW port of ncurses requires $TERM to be unset in order
+        to activate the Windows console driver.  */
+      if (s == NULL)
+       s = newterm ("unknown", stdout, stdin);
+#endif
+      if (s == NULL)
+       {
+         error (_("Cannot enable the TUI: error opening terminal [TERM=%s]"),
+                gdb_getenv_term ());
+       }
+      w = stdscr;
+
+      /* Check required terminal capabilities.  The MinGW port of
+        ncurses does have them, but doesn't expose them through "cup".  */
+#ifndef __MINGW32__
+      cap = tigetstr ("cup");
+      if (cap == NULL || cap == (char *) -1 || *cap == '\0')
+       {
+         endwin ();
+         delscreen (s);
+         error (_("Cannot enable the TUI: "
+                  "terminal doesn't support cursor addressing [TERM=%s]"),
+                gdb_getenv_term ());
+       }
 #endif
-  char *helpStr;
 
-  if (tui_version)
-    helpStr = "Toggle Specified Features\n\
-Usage:\ttoggle $fregs\n\ttoggle breakpoints";
+      cbreak ();
+      noecho ();
+      /* timeout (1); */
+      nodelay(w, FALSE);
+      nl();
+      keypad (w, TRUE);
+      rl_initialize ();
+      tui_set_term_height_to (LINES);
+      tui_set_term_width_to (COLS);
+      def_prog_mode ();
+
+      tui_show_frame_info (0);
+      tui_set_layout (SRC_COMMAND);
+      tui_set_win_focus_to (TUI_SRC_WIN);
+      keypad (TUI_CMD_WIN->generic.handle, TRUE);
+      wrefresh (TUI_CMD_WIN->generic.handle);
+      tui_finish_init = 0;
+    }
   else
-    helpStr = "Toggle Specified Features\nUsage:toggle breakpoints";
-  add_abbrev_prefix_cmd ("toggle",
-                        class_tui,
-                        _toggle_command,
-                        helpStr,
-                        &togglelist,
-                        "toggle ",
-                        1,
-                        &cmdlist);
-}                              /* _initialize_tui */
-
-
-/*
-   ** va_catch_errors().
-   **       General purpose function to execute a function, catching errors.
-   **       If there is no error, the value returned by 'func' is returned.
-   **       If there is error, then zero is returned.
-   **       Note that 'func' must take a variable argument list as well.
-   **
-   **       Must not be called with immediate_quit in effect (bad things might
-   **       happen, say we got a signal in the middle of a memcpy to quit_return).
-   **       This is an OK restriction; with very few exceptions immediate_quit can
-   **       be replaced by judicious use of QUIT.
- */
-Opaque
-#ifdef __STDC__
-va_catch_errors (
-                 TuiOpaqueFuncPtr func,
-                 va_list args)
-#else
-va_catch_errors (func, args)
-     TuiOpaqueFuncPtr func;
-     va_list args;
-#endif
-{
-  Opaque ret = (Opaque) NULL;
-
-  /*
-     ** We could have used catch_errors(), but it doesn't handle variable args.
-     ** Also, for the tui, we always want to catch all errors, so we don't
-     ** need to pass a mask, or an error string.
-   */
-  jmp_buf saved_error;
-  jmp_buf saved_quit;
-  jmp_buf tmp_jmp;
-  struct cleanup *saved_cleanup_chain;
-  char *saved_error_pre_print;
-  char *saved_quit_pre_print;
-  extern jmp_buf error_return;
-  extern jmp_buf quit_return;
-
-  saved_cleanup_chain = save_cleanups ();
-  saved_error_pre_print = error_pre_print;
-  saved_quit_pre_print = quit_pre_print;
-
-  memcpy ((char *) saved_error, (char *) error_return, sizeof (jmp_buf));
-  error_pre_print = "";
-  memcpy (saved_quit, quit_return, sizeof (jmp_buf));
-  quit_pre_print = "";
-
-  if (setjmp (tmp_jmp) == 0)
     {
-      va_list argList = args;
-      memcpy (error_return, tmp_jmp, sizeof (jmp_buf));
-      memcpy (quit_return, tmp_jmp, sizeof (jmp_buf));
-      ret = func (argList);
-    }
-  restore_cleanups (saved_cleanup_chain);
-  memcpy (error_return, saved_error, sizeof (jmp_buf));
-  error_pre_print = saved_error_pre_print;
-  memcpy (quit_return, saved_quit, sizeof (jmp_buf));
-  quit_pre_print = saved_quit_pre_print;
+     /* Save the current gdb setting of the terminal.
+        Curses will restore this state when endwin() is called.  */
+     def_shell_mode ();
+     clearok (stdscr, TRUE);
+   }
 
-  return ret;
-}
+  /* Install the TUI specific hooks.  */
+  tui_install_hooks ();
+  rl_startup_hook = tui_rl_startup_hook;
 
-/*
-   ** vcatch_errors().
-   **        Catch errors occurring in tui or non tui function, handling
-   **        variable param lists. Note that 'func' must take a variable
-   **        argument list as well.
- */
-Opaque
-#ifdef __STDC__
-vcatch_errors (
-               OpaqueFuncPtr func,...)
-#else
-vcatch_errors (va_alist)
-     va_dcl
-/*
-   vcatch_errors(func, va_alist)
-   OpaqueFuncPtr    func;
-   va_dcl
- */
-#endif
-{
-  Opaque ret = (Opaque) NULL;
-  va_list args;
-#ifdef __STDC__
-  va_start (args, func);
-/*
-   va_arg(args, OpaqueFuncPtr);
- */
-#else
-  OpaqueFuncPtr func;
-
-  va_start (args);
-  func = va_arg (args, OpaqueFuncPtr);
-#endif
-  ret = va_catch_errors (func, args);
-  va_end (args);
-
-  return ret;
-}
+  tui_update_variables ();
+  
+  tui_setup_io (1);
 
+  tui_active = 1;
 
-void
-#ifdef __STDC__
-strcat_to_buf (
-               char *buf,
-               int buflen,
-               char *itemToAdd)
-#else
-strcat_to_buf (buf, buflen, itemToAdd)
-     char *buf;
-     int buflen;
-     char *itemToAdd;
-#endif
-{
-  if (itemToAdd != (char *) NULL && buf != (char *) NULL)
+  /* Resize windows before anything might display/refresh a
+     window.  */
+  if (tui_win_resized ())
     {
-      if ((strlen (buf) + strlen (itemToAdd)) <= buflen)
-       strcat (buf, itemToAdd);
-      else
-       strncat (buf, itemToAdd, (buflen - strlen (buf)));
+      tui_set_win_resized_to (FALSE);
+      tui_resize_all ();
     }
 
-  return;
-}                              /* strcat_to_buf */
-
-/* VARARGS */
-void
-#ifdef ANSI_PROTOTYPES
-strcat_to_buf_with_fmt (
-                        char *buf,
-                        int bufLen,
-                        char *format,...)
-#else
-strcat_to_buf_with_fmt (va_alist)
-     va_dcl
-#endif
-{
-  char *linebuffer;
-  struct cleanup *old_cleanups;
-  va_list args;
-#ifdef ANSI_PROTOTYPES
-  va_start (args, format);
-#else
-  char *buf;
-  int bufLen;
-  char *format;
-
-  va_start (args);
-  buf = va_arg (args, char *);
-  bufLen = va_arg (args, int);
-  format = va_arg (args, char *);
-#endif
-  vasprintf (&linebuffer, format, args);
-  old_cleanups = make_cleanup (free, linebuffer);
-  strcat_to_buf (buf, bufLen, linebuffer);
-  do_cleanups (old_cleanups);
-  va_end (args);
-}
-
+  if (deprecated_safe_get_selected_frame ())
+    tui_show_frame_info (deprecated_safe_get_selected_frame ());
 
+  /* Restore TUI keymap.  */
+  tui_set_key_mode (tui_current_key_mode);
 
+  /* Refresh the screen.  */
+  tui_refresh_all_win ();
 
+  /* Update gdb's knowledge of its terminal.  */
+  gdb_save_tty_state ();
+  tui_update_gdb_sizes ();
+}
 
-/***********************
-** Static Functions
-************************/
-
-
-/*
-   ** _tui_vDo().
-   **        General purpose function to execute a tui function.  Transitions
-   **        between curses and the are handled here.  This function is called
-   **        by non-tui gdb functions.
-   **
-   **        Errors are caught here.
-   **        If there is no error, the value returned by 'func' is returned.
-   **        If there is an error, then zero is returned.
-   **
-   **       Must not be called with immediate_quit in effect (bad things might
-   **       happen, say we got a signal in the middle of a memcpy to quit_return).
-   **       This is an OK restriction; with very few exceptions immediate_quit can
-   **       be replaced by judicious use of QUIT.
- */
-static Opaque
-#ifdef __STDC__
-_tui_vDo (
-          TuiOpaqueFuncPtr func,
-          va_list args)
-#else
-_tui_vDo (func, args)
-     TuiOpaqueFuncPtr func;
-     va_list args;
-#endif
+/* Leave the tui mode.
+   Remove the tui hooks and configure the gdb output and readline
+   back to their original state.  The curses mode is left so that
+   the terminal setting is restored to the point when we entered.  */
+void
+tui_disable (void)
 {
-  extern int terminal_is_ours;
+  if (!tui_active)
+    return;
 
-  Opaque ret = (Opaque) NULL;
+  /* Restore initial readline keymap.  */
+  rl_set_keymap (tui_readline_standard_keymap);
 
-  /* It is an error to be tuiDo'ing if we
-     * don't own the terminal.
-   */
-  if (!terminal_is_ours)
-    return ret;
+  /* Remove TUI hooks.  */
+  tui_remove_hooks ();
+  rl_startup_hook = 0;
+  rl_already_prompted = 0;
 
-  if (tui_version)
-    {
-      /* If doing command window the "XDB way" (command window
-         * is unmanaged by curses...
-       */
-      /* Set up terminal for TUI */
-      tuiTermSetup (1);
+  /* Leave curses and restore previous gdb terminal setting.  */
+  endwin ();
 
-      ret = va_catch_errors (func, args);
+  /* gdb terminal has changed, update gdb internal copy of it
+     so that terminal management with the inferior works.  */
+  tui_setup_io (0);
 
-      /* Set up terminal for command window */
-      tuiTermUnsetup (1, cmdWin->detail.commandInfo.curch);
-    }
+  /* Update gdb's knowledge of its terminal.  */
+  gdb_save_tty_state ();
 
-  return ret;
-}                              /* _tui_vDo */
+  tui_active = 0;
+  tui_update_gdb_sizes ();
+}
 
+/* Command wrapper for enabling tui mode.  */
 
 static void
-#ifdef __STDC__
-_toggle_command (
-                 char *arg,
-                 int fromTTY)
-#else
-_toggle_command (arg, fromTTY)
-     char *arg;
-     int fromTTY;
-#endif
+tui_enable_command (char *args, int from_tty)
 {
-  printf_filtered ("Specify feature to toggle.\n%s\n",
-                  (tui_version) ? TUI_TOGGLE_USAGE : TOGGLE_USAGE);
-/*
-   tuiDo((TuiOpaqueFuncPtr)_Toggle_command, arg, fromTTY);
- */
+  tui_enable ();
 }
 
-/*
-   ** _tui_vToggle_command().
- */
+/* Command wrapper for leaving tui mode.  */
+
 static void
-#ifdef __STDC__
-_tui_vToggle_command (
-                      va_list args)
-#else
-_tui_vToggle_command (args)
-     va_list args;
-#endif
+tui_disable_command (char *args, int from_tty)
 {
-  char *arg;
-  int fromTTY;
-
-  arg = va_arg (args, char *);
+  tui_disable ();
+}
 
-  if (arg == (char *) NULL)
-    printf_filtered (TOGGLE_USAGE);
-  else
+void
+strcat_to_buf (char *buf, int buflen, 
+              const char *item_to_add)
+{
+  if (item_to_add != (char *) NULL && buf != (char *) NULL)
     {
-      char *ptr = (char *) tuiStrDup (arg);
-      int i;
-
-      for (i = 0; (ptr[i]); i++)
-       ptr[i] = toupper (arg[i]);
-
-      if (subsetCompare (ptr, TUI_FLOAT_REGS_NAME))
-       tuiToggleFloatRegs ();
-/*        else if (subsetCompare(ptr, "ANOTHER TOGGLE OPTION"))
-   ...
- */
+      if ((strlen (buf) + strlen (item_to_add)) <= buflen)
+       strcat (buf, item_to_add);
       else
-       printf_filtered (TOGGLE_USAGE);
-      tuiFree (ptr);
+       strncat (buf, item_to_add, (buflen - strlen (buf)));
     }
+}
 
-  return;
-}                              /* _tuiToggle_command */
+#if 0
+/* Solaris <sys/termios.h> defines CTRL.  */
+#ifndef CTRL
+#define CTRL(x)         (x & ~0140)
+#endif
 
+#define FILEDES         2
+#define CHK(val, dft)   (val<=0 ? dft : val)
 
 static void
-#ifdef __STDC__
-_tuiReset (void)
-#else
-_tuiReset ()
-#endif
+tui_reset (void)
 {
   struct termio mode;
 
-  /*
-     ** reset the teletype mode bits to a sensible state.
-     ** Copied tset.c
-   */
-#if ! defined (USG) && defined (TIOCGETC)
+  /* Reset the teletype mode bits to a sensible state.
+     Copied tset.c.  */
+#if defined (TIOCGETC)
   struct tchars tbuf;
-#endif /* !USG && TIOCGETC */
+#endif /* TIOCGETC */
 #ifdef UCB_NTTY
   struct ltchars ltc;
 
@@ -787,7 +603,6 @@ _tuiReset ()
       ioctl (FILEDES, TIOCSLTC, &ltc);
     }
 #endif /* UCB_NTTY */
-#ifndef USG
 #ifdef TIOCGETC
   ioctl (FILEDES, TIOCGETC, &tbuf);
   tbuf.t_intrc = CHK (tbuf.t_intrc, CTRL ('?'));
@@ -795,7 +610,7 @@ _tuiReset ()
   tbuf.t_startc = CHK (tbuf.t_startc, CTRL ('Q'));
   tbuf.t_stopc = CHK (tbuf.t_stopc, CTRL ('S'));
   tbuf.t_eofc = CHK (tbuf.t_eofc, CTRL ('D'));
-  /* brkc is left alone */
+  /* brkc is left alone */
   ioctl (FILEDES, TIOCSETC, &tbuf);
 #endif /* TIOCGETC */
   mode.sg_flags &= ~(RAW
@@ -804,27 +619,70 @@ _tuiReset ()
 #endif /* CBREAK */
                     | VTDELAY | ALLDELAY);
   mode.sg_flags |= XTABS | ECHO | CRMOD | ANYP;
-#else /*USG */
-  ioctl (FILEDES, TCGETA, &mode);
-  mode.c_cc[VINTR] = CHK (mode.c_cc[VINTR], CTRL ('?'));
-  mode.c_cc[VQUIT] = CHK (mode.c_cc[VQUIT], CTRL ('\\'));
-  mode.c_cc[VEOF] = CHK (mode.c_cc[VEOF], CTRL ('D'));
-
-  mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | INLCR | IGNCR | IUCLC | IXOFF);
-  mode.c_iflag |= (BRKINT | ISTRIP | ICRNL | IXON);
-  mode.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |
-                   NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
-  mode.c_oflag |= (OPOST | ONLCR);
-  mode.c_cflag &= ~(CSIZE | PARODD | CLOCAL);
-#ifndef hp9000s800
-  mode.c_cflag |= (CS8 | CREAD);
-#else /*hp9000s800 */
-  mode.c_cflag |= (CS8 | CSTOPB | CREAD);
-#endif /* hp9000s800 */
-  mode.c_lflag &= ~(XCASE | ECHONL | NOFLSH);
-  mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOK);
-  ioctl (FILEDES, TCSETAW, &mode);
-#endif /* USG */
 
   return;
-}                              /* _tuiReset */
+}
+#endif
+
+void
+tui_show_source (const char *fullname, int line)
+{
+  struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
+  /* Make sure that the source window is displayed.  */
+  tui_add_win_to_layout (SRC_WIN);
+
+  tui_update_source_windows_with_line (cursal.symtab, line);
+  tui_update_locator_fullname (fullname);
+}
+
+void
+tui_show_assembly (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  tui_add_win_to_layout (DISASSEM_WIN);
+  tui_update_source_windows_with_addr (gdbarch, addr);
+}
+
+int
+tui_is_window_visible (enum tui_win_type type)
+{
+  if (tui_active == 0)
+    return 0;
+
+  if (tui_win_list[type] == 0)
+    return 0;
+  
+  return tui_win_list[type]->generic.is_visible;
+}
+
+int
+tui_get_command_dimension (unsigned int *width, 
+                          unsigned int *height)
+{
+  if (!tui_active || (TUI_CMD_WIN == NULL))
+    {
+      return 0;
+    }
+  
+  *width = TUI_CMD_WIN->generic.width;
+  *height = TUI_CMD_WIN->generic.height;
+  return 1;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_tui;
+
+void
+_initialize_tui (void)
+{
+  struct cmd_list_element **tuicmd;
+
+  tuicmd = tui_get_cmd_list ();
+
+  add_cmd ("enable", class_tui, tui_enable_command,
+          _("Enable TUI display mode."),
+          tuicmd);
+  add_cmd ("disable", class_tui, tui_disable_command,
+          _("Disable TUI display mode."),
+          tuicmd);
+}