1/* TUI display locator.
2
3   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
4   Foundation, Inc.
5
6   Contributed by Hewlett-Packard Company.
7
8   This file is part of GDB.
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 2 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 59 Temple Place - Suite 330,
23   Boston, MA 02111-1307, USA.  */
24
25#include "defs.h"
26#include "symtab.h"
27#include "breakpoint.h"
28#include "frame.h"
29#include "command.h"
30#include "inferior.h"
31#include "target.h"
32#include "top.h"
33#include "gdb_string.h"
34#include "tui/tui.h"
35#include "tui/tui-data.h"
36#include "tui/tui-stack.h"
37#include "tui/tui-wingeneral.h"
38#include "tui/tui-source.h"
39#include "tui/tui-winsource.h"
40#include "tui/tui-file.h"
41
42#include "gdb_curses.h"
43
44/* Get a printable name for the function at the address.
45   The symbol name is demangled if demangling is turned on.
46   Returns a pointer to a static area holding the result.  */
47static char* tui_get_function_from_frame (struct frame_info *fi);
48
49/* Set the filename portion of the locator.  */
50static void tui_set_locator_filename (const char *filename);
51
52/* Update the locator, with the provided arguments.  */
53static void tui_set_locator_info (const char *filename, const char *procname,
54                                  int lineno, CORE_ADDR addr);
55
56static void tui_update_command (char *, int);
57
58
59/* Create the status line to display as much information as we
60   can on this single line: target name, process number, current
61   function, current line, current PC, SingleKey mode.  */
62static char*
63tui_make_status_line (struct tui_locator_element* loc)
64{
65  char* string;
66  char line_buf[50], *pname;
67  char* buf;
68  int status_size;
69  int i, proc_width;
70  const char* pid_name;
71  const char* pc_buf;
72  int target_width;
73  int pid_width;
74  int line_width;
75  int pc_width;
76  struct ui_file *pc_out;
77
78  if (ptid_equal (inferior_ptid, null_ptid))
79    pid_name = "No process";
80  else
81    pid_name = target_pid_to_str (inferior_ptid);
82
83  target_width = strlen (target_shortname);
84  if (target_width > MAX_TARGET_WIDTH)
85    target_width = MAX_TARGET_WIDTH;
86
87  pid_width = strlen (pid_name);
88  if (pid_width > MAX_PID_WIDTH)
89    pid_width = MAX_PID_WIDTH;
90
91  status_size = tui_term_width ();
92  string = (char *) xmalloc (status_size + 1);
93  buf = (char*) alloca (status_size + 1);
94
95  /* Translate line number and obtain its size.  */
96  if (loc->line_no > 0)
97    sprintf (line_buf, "%d", loc->line_no);
98  else
99    strcpy (line_buf, "??");
100  line_width = strlen (line_buf);
101  if (line_width < MIN_LINE_WIDTH)
102    line_width = MIN_LINE_WIDTH;
103
104  /* Translate PC address.  */
105  pc_out = tui_sfileopen (128);
106  print_address_numeric (loc->addr, 1, pc_out);
107  pc_buf = tui_file_get_strbuf (pc_out);
108  pc_width = strlen (pc_buf);
109
110  /* First determine the amount of proc name width we have available.
111     The +1 are for a space separator between fields.
112     The -1 are to take into account the \0 counted by sizeof.  */
113  proc_width = (status_size
114                - (target_width + 1)
115                - (pid_width + 1)
116                - (sizeof (PROC_PREFIX) - 1 + 1)
117                - (sizeof (LINE_PREFIX) - 1 + line_width + 1)
118                - (sizeof (PC_PREFIX) - 1 + pc_width + 1)
119                - (tui_current_key_mode == TUI_SINGLE_KEY_MODE
120                   ? (sizeof (SINGLE_KEY) - 1 + 1)
121                   : 0));
122
123  /* If there is no room to print the function name, try by removing
124     some fields.  */
125  if (proc_width < MIN_PROC_WIDTH)
126    {
127      proc_width += target_width + 1;
128      target_width = 0;
129      if (proc_width < MIN_PROC_WIDTH)
130        {
131          proc_width += pid_width + 1;
132          pid_width = 0;
133          if (proc_width <= MIN_PROC_WIDTH)
134            {
135              proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1;
136              pc_width = 0;
137              if (proc_width < 0)
138                {
139                  proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1;
140                  line_width = 0;
141                  if (proc_width < 0)
142                    proc_width = 0;
143                }
144            }
145        }
146    }
147
148  /* Now convert elements to string form */
149  pname = loc->proc_name;
150
151  /* Now create the locator line from the string version
152     of the elements.  We could use sprintf() here but
153     that wouldn't ensure that we don't overrun the size
154     of the allocated buffer.  strcat_to_buf() will.  */
155  *string = (char) 0;
156
157  if (target_width > 0)
158    {
159      sprintf (buf, "%*.*s ",
160               -target_width, target_width, target_shortname);
161      strcat_to_buf (string, status_size, buf);
162    }
163  if (pid_width > 0)
164    {
165      sprintf (buf, "%*.*s ",
166               -pid_width, pid_width, pid_name);
167      strcat_to_buf (string, status_size, buf);
168    }
169
170  /* Show whether we are in SingleKey mode.  */
171  if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
172    {
173      strcat_to_buf (string, status_size, SINGLE_KEY);
174      strcat_to_buf (string, status_size, " ");
175    }
176
177  /* procedure/class name */
178  if (proc_width > 0)
179    {
180      if (strlen (pname) > proc_width)
181        sprintf (buf, "%s%*.*s* ", PROC_PREFIX,
182                 1 - proc_width, proc_width - 1, pname);
183      else
184        sprintf (buf, "%s%*.*s ", PROC_PREFIX,
185                 -proc_width, proc_width, pname);
186      strcat_to_buf (string, status_size, buf);
187    }
188
189  if (line_width > 0)
190    {
191      sprintf (buf, "%s%*.*s ", LINE_PREFIX,
192               -line_width, line_width, line_buf);
193      strcat_to_buf (string, status_size, buf);
194    }
195  if (pc_width > 0)
196    {
197      strcat_to_buf (string, status_size, PC_PREFIX);
198      strcat_to_buf (string, status_size, pc_buf);
199    }
200
201
202  for (i = strlen (string); i < status_size; i++)
203    string[i] = ' ';
204  string[status_size] = (char) 0;
205
206  ui_file_delete (pc_out);
207  return string;
208}
209
210/* Get a printable name for the function at the address.
211   The symbol name is demangled if demangling is turned on.
212   Returns a pointer to a static area holding the result.  */
213static char*
214tui_get_function_from_frame (struct frame_info *fi)
215{
216  static char name[256];
217  struct ui_file *stream = tui_sfileopen (256);
218  char *p;
219
220  print_address_symbolic (get_frame_pc (fi), stream, demangle, "");
221  p = tui_file_get_strbuf (stream);
222
223  /* Use simple heuristics to isolate the function name.  The symbol can
224     be demangled and we can have function parameters.  Remove them because
225     the status line is too short to display them.  */
226  if (*p == '<')
227    p++;
228  strncpy (name, p, sizeof (name));
229  p = strchr (name, '(');
230  if (!p)
231    p = strchr (name, '>');
232  if (p)
233    *p = 0;
234  p = strchr (name, '+');
235  if (p)
236    *p = 0;
237  ui_file_delete (stream);
238  return name;
239}
240
241void
242tui_show_locator_content (void)
243{
244  char *string;
245  struct tui_gen_win_info * locator;
246
247  locator = tui_locator_win_info_ptr ();
248
249  if (locator != NULL && locator->handle != (WINDOW *) NULL)
250    {
251      struct tui_win_element * element;
252
253      element = (struct tui_win_element *) locator->content[0];
254
255      string = tui_make_status_line (&element->which_element.locator);
256      wmove (locator->handle, 0, 0);
257      wstandout (locator->handle);
258      waddstr (locator->handle, string);
259      wclrtoeol (locator->handle);
260      wstandend (locator->handle);
261      tui_refresh_win (locator);
262      wmove (locator->handle, 0, 0);
263      xfree (string);
264      locator->content_in_use = TRUE;
265    }
266}
267
268
269/* Set the filename portion of the locator.  */
270static void
271tui_set_locator_filename (const char *filename)
272{
273  struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
274  struct tui_locator_element * element;
275
276  if (locator->content[0] == NULL)
277    {
278      tui_set_locator_info (filename, NULL, 0, 0);
279      return;
280    }
281
282  element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
283  element->file_name[0] = 0;
284  strcat_to_buf (element->file_name, MAX_LOCATOR_ELEMENT_LEN, filename);
285}
286
287/* Update the locator, with the provided arguments.  */
288static void
289tui_set_locator_info (const char *filename, const char *procname, int lineno,
290                      CORE_ADDR addr)
291{
292  struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
293  struct tui_locator_element * element;
294
295  /* Allocate the locator content if necessary.  */
296  if (locator->content_size <= 0)
297    {
298      locator->content = (void **) tui_alloc_content (1, locator->type);
299      locator->content_size = 1;
300    }
301
302  element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
303  element->proc_name[0] = (char) 0;
304  strcat_to_buf (element->proc_name, MAX_LOCATOR_ELEMENT_LEN, procname);
305  element->line_no = lineno;
306  element->addr = addr;
307  tui_set_locator_filename (filename);
308}
309
310/* Update only the filename portion of the locator.  */
311void
312tui_update_locator_filename (const char *filename)
313{
314  tui_set_locator_filename (filename);
315  tui_show_locator_content ();
316}
317
318/* Function to print the frame information for the TUI.  */
319void
320tui_show_frame_info (struct frame_info *fi)
321{
322  struct tui_win_info * win_info;
323  int i;
324
325  if (fi)
326    {
327      int start_line, i;
328      CORE_ADDR low;
329      struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
330      int source_already_displayed;
331      struct symtab_and_line sal;
332
333      find_frame_sal (fi, &sal);
334
335      source_already_displayed = sal.symtab != 0
336        && tui_source_is_displayed (sal.symtab->filename);
337      tui_set_locator_info (sal.symtab == 0 ? "??" : sal.symtab->filename,
338                            tui_get_function_from_frame (fi),
339                            sal.line,
340                            get_frame_pc (fi));
341      tui_show_locator_content ();
342      start_line = 0;
343      for (i = 0; i < (tui_source_windows ())->count; i++)
344	{
345	  union tui_which_element *item;
346	  win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
347
348	  item = &((struct tui_win_element *) locator->content[0])->which_element;
349	  if (win_info == TUI_SRC_WIN)
350	    {
351	      start_line = (item->locator.line_no -
352			   (win_info->generic.viewport_height / 2)) + 1;
353	      if (start_line <= 0)
354		start_line = 1;
355	    }
356	  else
357	    {
358	      if (find_pc_partial_function (get_frame_pc (fi), (char **) NULL,
359					    &low, (CORE_ADDR) NULL) == 0)
360		error ("No function contains program counter for selected frame.\n");
361	      else
362		low = tui_get_low_disassembly_address (low, get_frame_pc (fi));
363	    }
364
365	  if (win_info == TUI_SRC_WIN)
366	    {
367	      union tui_line_or_address l;
368	      l.line_no = start_line;
369	      if (!(source_already_displayed
370		    && tui_line_is_displayed (item->locator.line_no, win_info, TRUE)))
371		tui_update_source_window (win_info, sal.symtab, l, TRUE);
372	      else
373		{
374		  l.line_no = item->locator.line_no;
375		  tui_set_is_exec_point_at (l, win_info);
376		}
377	    }
378	  else
379	    {
380	      if (win_info == TUI_DISASM_WIN)
381		{
382		  union tui_line_or_address a;
383		  a.addr = low;
384		  if (!tui_addr_is_displayed (item->locator.addr, win_info, TRUE))
385		    tui_update_source_window (win_info, sal.symtab, a, TRUE);
386		  else
387		    {
388		      a.addr = item->locator.addr;
389		      tui_set_is_exec_point_at (a, win_info);
390		    }
391		}
392	    }
393	  tui_update_exec_info (win_info);
394	}
395    }
396  else
397    {
398      tui_set_locator_info (NULL, NULL, 0, (CORE_ADDR) 0);
399      tui_show_locator_content ();
400      for (i = 0; i < (tui_source_windows ())->count; i++)
401	{
402	  win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
403	  tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
404	  tui_update_exec_info (win_info);
405	}
406    }
407}
408
409/* Function to initialize gdb commands, for tui window stack
410   manipulation.  */
411void
412_initialize_tui_stack (void)
413{
414  add_com ("update", class_tui, tui_update_command,
415           "Update the source window and locator to display the current "
416           "execution point.\n");
417}
418
419/* Command to update the display with the current execution point.  */
420static void
421tui_update_command (char *arg, int from_tty)
422{
423  char cmd[sizeof("frame 0")];
424
425  strcpy (cmd, "frame 0");
426  execute_command (cmd, from_tty);
427}
428