Home | History | Annotate | Line # | Download | only in tui
tui-regs.c revision 1.11
      1   1.1  christos /* TUI display registers in window.
      2   1.1  christos 
      3  1.11  christos    Copyright (C) 1998-2024 Free Software Foundation, Inc.
      4   1.1  christos 
      5   1.1  christos    Contributed by Hewlett-Packard Company.
      6   1.1  christos 
      7   1.1  christos    This file is part of GDB.
      8   1.1  christos 
      9   1.1  christos    This program is free software; you can redistribute it and/or modify
     10   1.1  christos    it under the terms of the GNU General Public License as published by
     11   1.1  christos    the Free Software Foundation; either version 3 of the License, or
     12   1.1  christos    (at your option) any later version.
     13   1.1  christos 
     14   1.1  christos    This program is distributed in the hope that it will be useful,
     15   1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16   1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17   1.1  christos    GNU General Public License for more details.
     18   1.1  christos 
     19   1.1  christos    You should have received a copy of the GNU General Public License
     20   1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     21   1.1  christos 
     22   1.1  christos #include "arch-utils.h"
     23   1.1  christos #include "tui/tui.h"
     24   1.1  christos #include "tui/tui-data.h"
     25   1.1  christos #include "symtab.h"
     26   1.1  christos #include "gdbtypes.h"
     27  1.11  christos #include "cli/cli-cmds.h"
     28   1.1  christos #include "frame.h"
     29   1.1  christos #include "regcache.h"
     30   1.1  christos #include "inferior.h"
     31   1.1  christos #include "target.h"
     32   1.1  christos #include "tui/tui-layout.h"
     33   1.1  christos #include "tui/tui-win.h"
     34   1.1  christos #include "tui/tui-wingeneral.h"
     35   1.1  christos #include "tui/tui-file.h"
     36   1.1  christos #include "tui/tui-regs.h"
     37   1.3  christos #include "tui/tui-io.h"
     38   1.1  christos #include "reggroups.h"
     39   1.1  christos #include "valprint.h"
     40   1.5  christos #include "completer.h"
     41   1.1  christos 
     42   1.1  christos #include "gdb_curses.h"
     43   1.1  christos 
     44   1.9  christos /* A subclass of string_file that expands tab characters.  */
     45   1.9  christos class tab_expansion_file : public string_file
     46   1.9  christos {
     47   1.9  christos public:
     48   1.1  christos 
     49   1.9  christos   tab_expansion_file () = default;
     50   1.1  christos 
     51   1.9  christos   void write (const char *buf, long length_buf) override;
     52   1.1  christos 
     53   1.9  christos private:
     54   1.1  christos 
     55   1.9  christos   int m_column = 0;
     56   1.9  christos };
     57   1.1  christos 
     58   1.9  christos void
     59   1.9  christos tab_expansion_file::write (const char *buf, long length_buf)
     60   1.9  christos {
     61   1.9  christos   for (long i = 0; i < length_buf; ++i)
     62   1.9  christos     {
     63   1.9  christos       if (buf[i] == '\t')
     64   1.9  christos 	{
     65   1.9  christos 	  do
     66   1.9  christos 	    {
     67   1.9  christos 	      string_file::write (" ", 1);
     68   1.9  christos 	      ++m_column;
     69   1.9  christos 	    }
     70   1.9  christos 	  while ((m_column % 8) != 0);
     71   1.9  christos 	}
     72   1.9  christos       else
     73   1.9  christos 	{
     74   1.9  christos 	  string_file::write (&buf[i], 1);
     75   1.9  christos 	  if (buf[i] == '\n')
     76   1.9  christos 	    m_column = 0;
     77   1.9  christos 	  else
     78   1.9  christos 	    ++m_column;
     79   1.9  christos 	}
     80   1.9  christos     }
     81   1.9  christos }
     82   1.1  christos 
     83   1.9  christos /* Get the register from the frame and return a printable
     84   1.9  christos    representation of it.  */
     85   1.1  christos 
     86   1.9  christos static std::string
     87  1.11  christos tui_register_format (const frame_info_ptr &frame, int regnum)
     88   1.1  christos {
     89   1.9  christos   struct gdbarch *gdbarch = get_frame_arch (frame);
     90   1.9  christos 
     91   1.9  christos   /* Expand tabs into spaces, since ncurses on MS-Windows doesn't.  */
     92   1.9  christos   tab_expansion_file stream;
     93   1.9  christos   gdbarch_print_registers_info (gdbarch, &stream, frame, regnum, 1);
     94   1.1  christos 
     95   1.9  christos   /* Remove the possible \n.  */
     96  1.10  christos   std::string str = stream.release ();
     97   1.9  christos   if (!str.empty () && str.back () == '\n')
     98  1.11  christos     str.pop_back ();
     99   1.9  christos 
    100   1.9  christos   return str;
    101   1.9  christos }
    102   1.9  christos 
    103  1.11  christos /* Compute the register value from the given frame and format it for
    104  1.11  christos    the display.  update 'content' and set 'highlight' if the contents
    105  1.11  christos    changed.  */
    106  1.11  christos void
    107  1.11  christos tui_register_info::update (const frame_info_ptr &frame)
    108  1.11  christos {
    109  1.11  christos   std::string new_content = tui_register_format (frame, m_regno);
    110  1.11  christos   highlight = content != new_content;
    111  1.11  christos   content = std::move (new_content);
    112   1.9  christos }
    113   1.9  christos 
    114   1.9  christos /* See tui-regs.h.  */
    115   1.9  christos 
    116   1.9  christos int
    117   1.9  christos tui_data_window::last_regs_line_no () const
    118   1.9  christos {
    119   1.9  christos   int num_lines = m_regs_content.size () / m_regs_column_count;
    120   1.9  christos   if (m_regs_content.size () % m_regs_column_count)
    121   1.9  christos     num_lines++;
    122   1.1  christos   return num_lines;
    123   1.1  christos }
    124   1.1  christos 
    125   1.9  christos /* See tui-regs.h.  */
    126   1.1  christos 
    127   1.1  christos int
    128   1.9  christos tui_data_window::line_from_reg_element_no (int element_no) const
    129   1.1  christos {
    130   1.9  christos   if (element_no < m_regs_content.size ())
    131   1.1  christos     {
    132   1.1  christos       int i, line = (-1);
    133   1.1  christos 
    134   1.1  christos       i = 1;
    135   1.1  christos       while (line == (-1))
    136   1.1  christos 	{
    137   1.9  christos 	  if (element_no < m_regs_column_count * i)
    138   1.1  christos 	    line = i - 1;
    139   1.1  christos 	  else
    140   1.1  christos 	    i++;
    141   1.1  christos 	}
    142   1.1  christos 
    143   1.1  christos       return line;
    144   1.1  christos     }
    145   1.1  christos   else
    146   1.1  christos     return (-1);
    147   1.1  christos }
    148   1.1  christos 
    149   1.9  christos /* See tui-regs.h.  */
    150   1.1  christos 
    151   1.1  christos int
    152   1.9  christos tui_data_window::first_reg_element_no_inline (int line_no) const
    153   1.1  christos {
    154   1.9  christos   if (line_no * m_regs_column_count <= m_regs_content.size ())
    155   1.9  christos     return ((line_no + 1) * m_regs_column_count) - m_regs_column_count;
    156   1.1  christos   else
    157   1.1  christos     return (-1);
    158   1.1  christos }
    159   1.1  christos 
    160   1.1  christos /* Show the registers of the given group in the data window
    161   1.1  christos    and refresh the window.  */
    162   1.1  christos void
    163  1.11  christos tui_data_window::set_register_group (const reggroup *group)
    164   1.1  christos {
    165  1.11  christos   update_register_data (group);
    166   1.9  christos   rerender ();
    167   1.1  christos }
    168   1.1  christos 
    169   1.1  christos /* Set the data window to display the registers of the register group
    170  1.11  christos    using the given frame.  */
    171   1.1  christos 
    172   1.9  christos void
    173  1.11  christos tui_data_window::update_register_data (const reggroup *group)
    174   1.1  christos {
    175  1.11  christos   if (group == nullptr)
    176  1.11  christos     group = general_reggroup;
    177  1.11  christos 
    178  1.11  christos   if (!target_has_registers ()
    179  1.11  christos       || !target_has_stack ()
    180  1.11  christos       || !target_has_memory ())
    181  1.11  christos     {
    182  1.11  christos       set_title (_("Registers"));
    183  1.11  christos       m_current_group = nullptr;
    184  1.11  christos       m_gdbarch = nullptr;
    185  1.11  christos       m_regs_content.clear ();
    186  1.11  christos       return;
    187  1.11  christos     }
    188  1.11  christos 
    189  1.11  christos   frame_info_ptr frame = get_selected_frame (nullptr);
    190   1.1  christos   struct gdbarch *gdbarch = get_frame_arch (frame);
    191   1.1  christos 
    192  1.11  christos   if (m_current_group == group && m_gdbarch == gdbarch)
    193   1.1  christos     {
    194  1.11  christos       /* Nothing to do here.  */
    195  1.11  christos       return;
    196  1.11  christos     }
    197   1.1  christos 
    198  1.11  christos   m_current_group = group;
    199  1.11  christos   m_gdbarch = gdbarch;
    200   1.1  christos 
    201  1.11  christos   /* Make a new title showing which group we display.  */
    202  1.11  christos   this->set_title (string_printf ("Register group: %s", group->name ()));
    203   1.1  christos 
    204  1.11  christos   /* Create the registers.  */
    205  1.11  christos   m_regs_content.clear ();
    206   1.9  christos 
    207  1.11  christos   for (int regnum = 0;
    208  1.11  christos        regnum < gdbarch_num_cooked_regs (gdbarch);
    209  1.11  christos        regnum++)
    210   1.1  christos     {
    211   1.9  christos       /* Must be in the group.  */
    212   1.9  christos       if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
    213   1.9  christos 	continue;
    214   1.9  christos 
    215   1.9  christos       /* If the register name is empty, it is undefined for this
    216   1.9  christos 	 processor, so don't display anything.  */
    217  1.11  christos       const char *name = gdbarch_register_name (gdbarch, regnum);
    218  1.10  christos       if (*name == '\0')
    219   1.9  christos 	continue;
    220   1.9  christos 
    221  1.11  christos       m_regs_content.emplace_back (regnum, frame);
    222   1.1  christos     }
    223   1.9  christos }
    224   1.9  christos 
    225   1.9  christos /* See tui-regs.h.  */
    226   1.1  christos 
    227   1.9  christos void
    228   1.9  christos tui_data_window::display_registers_from (int start_element_no)
    229   1.9  christos {
    230  1.11  christos   werase (handle.get ());
    231  1.11  christos   check_and_display_highlight_if_needed ();
    232  1.11  christos 
    233  1.11  christos   /* In case the regs window is not boxed, we'll write the last char in the
    234  1.11  christos      last line here, causing a scroll, so prevent that.  */
    235  1.11  christos   scrollok (handle.get (), FALSE);
    236  1.11  christos 
    237   1.9  christos   int max_len = 0;
    238   1.9  christos   for (auto &&data_item_win : m_regs_content)
    239   1.1  christos     {
    240   1.9  christos       int len = data_item_win.content.size ();
    241   1.9  christos 
    242   1.9  christos       if (len > max_len)
    243   1.9  christos 	max_len = len;
    244   1.1  christos     }
    245   1.9  christos   m_item_width = max_len + 1;
    246  1.10  christos 
    247  1.10  christos   int i;
    248  1.10  christos   /* Mark register windows above the visible area.  */
    249  1.10  christos   for (i = 0; i < start_element_no; i++)
    250  1.10  christos     m_regs_content[i].y = 0;
    251   1.1  christos 
    252  1.11  christos   m_regs_column_count = (width - box_size ()) / m_item_width;
    253   1.9  christos   if (m_regs_column_count == 0)
    254   1.9  christos     m_regs_column_count = 1;
    255  1.11  christos   m_item_width = (width - box_size ()) / m_regs_column_count;
    256   1.9  christos 
    257   1.9  christos   /* Now create each data "sub" window, and write the display into
    258   1.9  christos      it.  */
    259  1.11  christos   int cur_y = box_width ();
    260  1.11  christos   while (i < m_regs_content.size () && cur_y <= height - box_size ())
    261   1.1  christos     {
    262   1.9  christos       for (int j = 0;
    263   1.9  christos 	   j < m_regs_column_count && i < m_regs_content.size ();
    264   1.9  christos 	   j++)
    265   1.1  christos 	{
    266   1.9  christos 	  /* Create the window if necessary.  */
    267  1.11  christos 	  m_regs_content[i].x = box_width () + (m_item_width * j);
    268   1.9  christos 	  m_regs_content[i].y = cur_y;
    269   1.9  christos 	  m_regs_content[i].rerender (handle.get (), m_item_width);
    270   1.9  christos 	  i++;		/* Next register.  */
    271   1.1  christos 	}
    272   1.9  christos       cur_y++;		/* Next row.  */
    273   1.9  christos     }
    274  1.10  christos 
    275  1.10  christos   /* Mark register windows below the visible area.  */
    276  1.10  christos   for (; i < m_regs_content.size (); i++)
    277  1.10  christos     m_regs_content[i].y = 0;
    278  1.10  christos 
    279  1.10  christos   refresh_window ();
    280   1.9  christos }
    281   1.1  christos 
    282   1.9  christos /* See tui-regs.h.  */
    283   1.9  christos 
    284   1.9  christos void
    285   1.9  christos tui_data_window::display_reg_element_at_line (int start_element_no,
    286   1.9  christos 					      int start_line_no)
    287   1.9  christos {
    288   1.9  christos   int element_no = start_element_no;
    289   1.9  christos 
    290   1.9  christos   if (start_element_no != 0 && start_line_no != 0)
    291   1.9  christos     {
    292   1.9  christos       int last_line_no, first_line_on_last_page;
    293   1.1  christos 
    294   1.9  christos       last_line_no = last_regs_line_no ();
    295  1.11  christos       first_line_on_last_page = last_line_no - (height - box_size ());
    296   1.9  christos       if (first_line_on_last_page < 0)
    297   1.9  christos 	first_line_on_last_page = 0;
    298   1.1  christos 
    299   1.9  christos       /* If the element_no causes us to scroll past the end of the
    300   1.9  christos 	 registers, adjust what element to really start the
    301   1.9  christos 	 display at.  */
    302   1.9  christos       if (start_line_no > first_line_on_last_page)
    303   1.9  christos 	element_no = first_reg_element_no_inline (first_line_on_last_page);
    304   1.1  christos     }
    305   1.9  christos   display_registers_from (element_no);
    306   1.1  christos }
    307   1.1  christos 
    308   1.9  christos /* See tui-regs.h.  */
    309   1.1  christos 
    310   1.9  christos int
    311   1.9  christos tui_data_window::display_registers_from_line (int line_no)
    312   1.1  christos {
    313   1.9  christos   int element_no;
    314   1.9  christos 
    315   1.9  christos   if (line_no < 0)
    316   1.9  christos     line_no = 0;
    317   1.9  christos   else
    318   1.1  christos     {
    319   1.9  christos       /* Make sure that we don't display off the end of the
    320   1.9  christos 	 registers.  */
    321   1.9  christos       if (line_no >= last_regs_line_no ())
    322   1.9  christos 	{
    323   1.9  christos 	  line_no = line_from_reg_element_no (m_regs_content.size () - 1);
    324   1.9  christos 	  if (line_no < 0)
    325   1.9  christos 	    line_no = 0;
    326   1.9  christos 	}
    327   1.9  christos     }
    328   1.9  christos 
    329   1.9  christos   element_no = first_reg_element_no_inline (line_no);
    330   1.9  christos   if (element_no < m_regs_content.size ())
    331   1.9  christos     display_reg_element_at_line (element_no, line_no);
    332   1.9  christos   else
    333   1.9  christos     line_no = (-1);
    334   1.9  christos 
    335   1.9  christos   return line_no;
    336   1.9  christos }
    337   1.1  christos 
    338   1.1  christos 
    339   1.9  christos /* Answer the index first element displayed.  If none are displayed,
    340   1.9  christos    then return (-1).  */
    341   1.9  christos int
    342   1.9  christos tui_data_window::first_data_item_displayed ()
    343   1.9  christos {
    344   1.9  christos   for (int i = 0; i < m_regs_content.size (); i++)
    345   1.9  christos     {
    346  1.11  christos       if (m_regs_content[i].visible ())
    347   1.9  christos 	return i;
    348   1.1  christos     }
    349   1.9  christos 
    350   1.9  christos   return -1;
    351   1.1  christos }
    352   1.1  christos 
    353   1.9  christos void
    354  1.11  christos tui_data_window::erase_data_content ()
    355   1.9  christos {
    356  1.11  christos   center_string (_("[ Register Values Unavailable ]"));
    357   1.9  christos }
    358   1.9  christos 
    359   1.9  christos /* See tui-regs.h.  */
    360   1.1  christos 
    361   1.9  christos void
    362   1.9  christos tui_data_window::rerender ()
    363   1.9  christos {
    364   1.9  christos   if (m_regs_content.empty ())
    365  1.11  christos     erase_data_content ();
    366   1.9  christos   else
    367  1.11  christos     display_registers_from (0);
    368  1.11  christos   tui_wrefresh (handle.get ());
    369   1.9  christos }
    370   1.9  christos 
    371   1.9  christos 
    372   1.9  christos /* Scroll the data window vertically forward or backward.  */
    373   1.9  christos void
    374   1.9  christos tui_data_window::do_scroll_vertical (int num_to_scroll)
    375   1.9  christos {
    376   1.9  christos   int first_element_no;
    377   1.9  christos   int first_line = (-1);
    378   1.1  christos 
    379   1.9  christos   first_element_no = first_data_item_displayed ();
    380   1.9  christos   if (first_element_no < m_regs_content.size ())
    381   1.9  christos     first_line = line_from_reg_element_no (first_element_no);
    382   1.9  christos   else
    383   1.9  christos     { /* Calculate the first line from the element number which is in
    384  1.10  christos 	the general data content.  */
    385   1.1  christos     }
    386   1.1  christos 
    387   1.9  christos   if (first_line >= 0)
    388   1.9  christos     {
    389   1.9  christos       first_line += num_to_scroll;
    390   1.9  christos       display_registers_from_line (first_line);
    391   1.9  christos     }
    392   1.1  christos }
    393   1.1  christos 
    394   1.1  christos /* This function check all displayed registers for changes in values,
    395   1.1  christos    given a particular frame.  If the values have changed, they are
    396   1.1  christos    updated with the new value and highlighted.  */
    397   1.1  christos void
    398  1.11  christos tui_data_window::check_register_values (const frame_info_ptr &frame)
    399   1.1  christos {
    400  1.11  christos   if (frame == nullptr)
    401  1.11  christos     set_register_group (nullptr);
    402   1.9  christos   else
    403   1.1  christos     {
    404  1.11  christos       /* If the frame architecture changed, we need to reset the
    405  1.11  christos 	 register group.  */
    406  1.11  christos       struct gdbarch *gdbarch = get_frame_arch (frame);
    407  1.11  christos       if (gdbarch != m_gdbarch)
    408  1.11  christos 	set_register_group (nullptr);
    409  1.11  christos       else
    410   1.9  christos 	{
    411  1.11  christos 	  for (tui_register_info &data_item_win : m_regs_content)
    412  1.11  christos 	    {
    413  1.11  christos 	      bool was_hilighted = data_item_win.highlight;
    414   1.9  christos 
    415  1.11  christos 	      data_item_win.update (frame);
    416   1.1  christos 
    417  1.11  christos 	      /* Register windows whose y == 0 are outside the visible area.  */
    418  1.11  christos 	      if ((data_item_win.highlight || was_hilighted)
    419  1.11  christos 		  && data_item_win.visible ())
    420  1.11  christos 		data_item_win.rerender (handle.get (), m_item_width);
    421  1.11  christos 	    }
    422   1.1  christos 	}
    423  1.11  christos       tui_wrefresh (handle.get ());
    424   1.1  christos     }
    425   1.1  christos }
    426   1.1  christos 
    427   1.1  christos /* Display a register in a window.  If hilite is TRUE, then the value
    428   1.1  christos    will be displayed in reverse video.  */
    429   1.9  christos void
    430  1.11  christos tui_register_info::rerender (WINDOW *handle, int field_width)
    431   1.1  christos {
    432   1.9  christos   if (highlight)
    433   1.9  christos     /* We ignore the return value, casting it to void in order to avoid
    434   1.9  christos        a compiler warning.  The warning itself was introduced by a patch
    435   1.9  christos        to ncurses 5.7 dated 2009-08-29, changing this macro to expand
    436   1.9  christos        to code that causes the compiler to generate an unused-value
    437   1.9  christos        warning.  */
    438   1.9  christos     (void) wstandout (handle);
    439   1.9  christos 
    440   1.9  christos   mvwaddnstr (handle, y, x, content.c_str (), field_width - 1);
    441  1.10  christos   if (content.size () < field_width)
    442  1.10  christos     waddstr (handle, n_spaces (field_width - content.size ()));
    443   1.1  christos 
    444   1.9  christos   if (highlight)
    445   1.9  christos     /* We ignore the return value, casting it to void in order to avoid
    446   1.9  christos        a compiler warning.  The warning itself was introduced by a patch
    447   1.9  christos        to ncurses 5.7 dated 2009-08-29, changing this macro to expand
    448   1.9  christos        to code that causes the compiler to generate an unused-value
    449   1.9  christos        warning.  */
    450   1.9  christos     (void) wstandend (handle);
    451   1.1  christos }
    452   1.1  christos 
    453  1.10  christos /* Helper for "tui reg next", returns the next register group after
    454  1.10  christos    CURRENT_GROUP in the register group list for GDBARCH, with wrap around
    455  1.10  christos    behaviour.
    456  1.10  christos 
    457  1.10  christos    If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
    458  1.10  christos    just been displayed and has no current group selected) or the currently
    459  1.10  christos    selected register group can't be found (e.g. if the architecture has
    460  1.10  christos    changed since the register window was last updated), then the first
    461  1.10  christos    register group will be returned.  */
    462  1.10  christos 
    463  1.10  christos static const reggroup *
    464  1.10  christos tui_reg_next (const reggroup *current_group, struct gdbarch *gdbarch)
    465  1.10  christos {
    466  1.10  christos   const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
    467  1.10  christos   auto it = std::find (groups.begin (), groups.end (), current_group);
    468  1.10  christos   if (it != groups.end ())
    469  1.10  christos     it++;
    470  1.10  christos   if (it == groups.end ())
    471  1.10  christos     return groups.front ();
    472  1.10  christos   return *it;
    473  1.10  christos }
    474  1.10  christos 
    475  1.10  christos /* Helper for "tui reg prev", returns the register group previous to
    476  1.10  christos    CURRENT_GROUP in the register group list for GDBARCH, with wrap around
    477  1.10  christos    behaviour.
    478  1.10  christos 
    479  1.10  christos    If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
    480  1.10  christos    just been displayed and has no current group selected) or the currently
    481  1.10  christos    selected register group can't be found (e.g. if the architecture has
    482  1.10  christos    changed since the register window was last updated), then the last
    483  1.10  christos    register group will be returned.  */
    484  1.10  christos 
    485  1.10  christos static const reggroup *
    486  1.10  christos tui_reg_prev (const reggroup *current_group, struct gdbarch *gdbarch)
    487  1.10  christos {
    488  1.10  christos   const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
    489  1.10  christos   auto it = std::find (groups.rbegin (), groups.rend (), current_group);
    490  1.10  christos   if (it != groups.rend ())
    491  1.10  christos     it++;
    492  1.10  christos   if (it == groups.rend ())
    493  1.10  christos     return groups.back ();
    494  1.10  christos   return *it;
    495   1.1  christos }
    496   1.1  christos 
    497   1.5  christos /* Implement the 'tui reg' command.  Changes the register group displayed
    498   1.5  christos    in the tui register window.  Displays the tui register window if it is
    499   1.5  christos    not already on display.  */
    500   1.5  christos 
    501   1.1  christos static void
    502   1.8  christos tui_reg_command (const char *args, int from_tty)
    503   1.1  christos {
    504   1.5  christos   struct gdbarch *gdbarch = get_current_arch ();
    505   1.5  christos 
    506   1.5  christos   if (args != NULL)
    507   1.5  christos     {
    508   1.5  christos       size_t len = strlen (args);
    509   1.5  christos 
    510   1.5  christos       /* Make sure the curses mode is enabled.  */
    511   1.5  christos       tui_enable ();
    512   1.5  christos 
    513   1.9  christos       tui_suppress_output suppress;
    514   1.9  christos 
    515   1.5  christos       /* Make sure the register window is visible.  If not, select an
    516   1.5  christos 	 appropriate layout.  We need to do this before trying to run the
    517   1.5  christos 	 'next' or 'prev' commands.  */
    518   1.9  christos       if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
    519   1.9  christos 	tui_regs_layout ();
    520   1.5  christos 
    521  1.10  christos       const reggroup *match = nullptr;
    522  1.10  christos       const reggroup *current_group = TUI_DATA_WIN->get_current_group ();
    523   1.5  christos       if (strncmp (args, "next", len) == 0)
    524   1.9  christos 	match = tui_reg_next (current_group, gdbarch);
    525   1.5  christos       else if (strncmp (args, "prev", len) == 0)
    526   1.9  christos 	match = tui_reg_prev (current_group, gdbarch);
    527  1.10  christos       else
    528   1.5  christos 	{
    529  1.10  christos 	  /* This loop matches on the initial part of a register group
    530  1.10  christos 	     name.  If this initial part in ARGS matches only one register
    531  1.10  christos 	     group then the switch is made.  */
    532  1.10  christos 	  for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
    533   1.5  christos 	    {
    534  1.10  christos 	      if (strncmp (group->name (), args, len) == 0)
    535  1.10  christos 		{
    536  1.10  christos 		  if (match != NULL)
    537  1.10  christos 		    error (_("ambiguous register group name '%s'"), args);
    538  1.10  christos 		  match = group;
    539  1.10  christos 		}
    540   1.5  christos 	    }
    541   1.5  christos 	}
    542   1.5  christos 
    543   1.5  christos       if (match == NULL)
    544   1.5  christos 	error (_("unknown register group '%s'"), args);
    545   1.5  christos 
    546  1.11  christos       TUI_DATA_WIN->set_register_group (match);
    547   1.5  christos     }
    548   1.5  christos   else
    549   1.5  christos     {
    550  1.10  christos       gdb_printf (_("\"tui reg\" must be followed by the name of "
    551  1.10  christos 		    "either a register group,\nor one of 'next' "
    552  1.10  christos 		    "or 'prev'.  Known register groups are:\n"));
    553   1.5  christos 
    554  1.10  christos       bool first = true;
    555  1.10  christos       for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
    556   1.5  christos 	{
    557   1.5  christos 	  if (!first)
    558  1.10  christos 	    gdb_printf (", ");
    559  1.10  christos 	  first = false;
    560  1.10  christos 	  gdb_printf ("%s", group->name ());
    561   1.5  christos 	}
    562   1.5  christos 
    563  1.10  christos       gdb_printf ("\n");
    564   1.5  christos     }
    565   1.1  christos }
    566   1.1  christos 
    567   1.5  christos /* Complete names of register groups, and add the special "prev" and "next"
    568   1.5  christos    names.  */
    569   1.5  christos 
    570   1.8  christos static void
    571   1.5  christos tui_reggroup_completer (struct cmd_list_element *ignore,
    572   1.8  christos 			completion_tracker &tracker,
    573   1.5  christos 			const char *text, const char *word)
    574   1.1  christos {
    575   1.9  christos   static const char * const extra[] = { "next", "prev", NULL };
    576   1.5  christos 
    577   1.8  christos   reggroup_completer (ignore, tracker, text, word);
    578   1.1  christos 
    579   1.9  christos   complete_on_enum (tracker, extra, text, word);
    580   1.1  christos }
    581   1.1  christos 
    582   1.9  christos void _initialize_tui_regs ();
    583   1.1  christos void
    584   1.9  christos _initialize_tui_regs ()
    585   1.1  christos {
    586   1.5  christos   struct cmd_list_element **tuicmd, *cmd;
    587   1.1  christos 
    588   1.1  christos   tuicmd = tui_get_cmd_list ();
    589   1.1  christos 
    590   1.5  christos   cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
    591   1.9  christos TUI command to control the register window.\n\
    592   1.9  christos Usage: tui reg NAME\n\
    593   1.9  christos NAME is the name of the register group to display"), tuicmd);
    594   1.5  christos   set_cmd_completer (cmd, tui_reggroup_completer);
    595   1.1  christos }
    596