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