Change tui_make_status_line to return std::string
[binutils-gdb.git] / gdb / tui / tui-stack.c
1 /* TUI display locator.
2
3 Copyright (C) 1998-2019 Free Software Foundation, Inc.
4
5 Contributed by Hewlett-Packard Company.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "defs.h"
23 #include "symtab.h"
24 #include "breakpoint.h"
25 #include "frame.h"
26 #include "command.h"
27 #include "inferior.h"
28 #include "target.h"
29 #include "top.h"
30 #include "gdb-demangle.h"
31 #include "source.h"
32 #include "tui/tui.h"
33 #include "tui/tui-data.h"
34 #include "tui/tui-stack.h"
35 #include "tui/tui-wingeneral.h"
36 #include "tui/tui-source.h"
37 #include "tui/tui-winsource.h"
38 #include "tui/tui-file.h"
39
40 #include "gdb_curses.h"
41
42 #define PROC_PREFIX "In: "
43 #define LINE_PREFIX "L"
44 #define PC_PREFIX "PC: "
45
46 /* Minimum/Maximum length of some fields displayed in the TUI status
47 line. */
48 #define MIN_LINE_WIDTH 4 /* Use at least 4 digits for line
49 numbers. */
50 #define MIN_PROC_WIDTH 12
51 #define MAX_TARGET_WIDTH 10
52 #define MAX_PID_WIDTH 19
53
54 static struct tui_locator_window _locator;
55
56 \f
57
58 /* Accessor for the locator win info. Answers a pointer to the static
59 locator win info struct. */
60 struct tui_locator_window *
61 tui_locator_win_info_ptr (void)
62 {
63 return &_locator;
64 }
65
66 /* Create the status line to display as much information as we can on
67 this single line: target name, process number, current function,
68 current line, current PC, SingleKey mode. */
69 static std::string
70 tui_make_status_line (struct tui_locator_window *loc)
71 {
72 char line_buf[50], *pname;
73 int status_size;
74 int proc_width;
75 const char *pid_name;
76 int target_width;
77 int pid_width;
78 int line_width;
79
80 std::string pid_name_holder;
81 if (inferior_ptid == null_ptid)
82 pid_name = "No process";
83 else
84 {
85 pid_name_holder = target_pid_to_str (inferior_ptid);
86 pid_name = pid_name_holder.c_str ();
87 }
88
89 target_width = strlen (target_shortname);
90 if (target_width > MAX_TARGET_WIDTH)
91 target_width = MAX_TARGET_WIDTH;
92
93 pid_width = strlen (pid_name);
94 if (pid_width > MAX_PID_WIDTH)
95 pid_width = MAX_PID_WIDTH;
96
97 status_size = tui_term_width ();
98
99 /* Translate line number and obtain its size. */
100 if (loc->line_no > 0)
101 xsnprintf (line_buf, sizeof (line_buf), "%d", loc->line_no);
102 else
103 strcpy (line_buf, "??");
104 line_width = strlen (line_buf);
105 if (line_width < MIN_LINE_WIDTH)
106 line_width = MIN_LINE_WIDTH;
107
108 /* Translate PC address. */
109 std::string pc_out (loc->gdbarch
110 ? paddress (loc->gdbarch, loc->addr)
111 : "??");
112 const char *pc_buf = pc_out.c_str ();
113 int pc_width = pc_out.size ();
114
115 /* First determine the amount of proc name width we have available.
116 The +1 are for a space separator between fields.
117 The -1 are to take into account the \0 counted by sizeof. */
118 proc_width = (status_size
119 - (target_width + 1)
120 - (pid_width + 1)
121 - (sizeof (PROC_PREFIX) - 1 + 1)
122 - (sizeof (LINE_PREFIX) - 1 + line_width + 1)
123 - (sizeof (PC_PREFIX) - 1 + pc_width + 1)
124 - (tui_current_key_mode == TUI_SINGLE_KEY_MODE
125 ? (sizeof (SINGLE_KEY) - 1 + 1)
126 : 0));
127
128 /* If there is no room to print the function name, try by removing
129 some fields. */
130 if (proc_width < MIN_PROC_WIDTH)
131 {
132 proc_width += target_width + 1;
133 target_width = 0;
134 if (proc_width < MIN_PROC_WIDTH)
135 {
136 proc_width += pid_width + 1;
137 pid_width = 0;
138 if (proc_width <= MIN_PROC_WIDTH)
139 {
140 proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1;
141 pc_width = 0;
142 if (proc_width < 0)
143 {
144 proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1;
145 line_width = 0;
146 if (proc_width < 0)
147 proc_width = 0;
148 }
149 }
150 }
151 }
152
153 /* Now convert elements to string form. */
154 pname = loc->proc_name;
155
156 /* Now create the locator line from the string version of the
157 elements. */
158 string_file string;
159
160 if (target_width > 0)
161 string.printf ("%*.*s ", -target_width, target_width, target_shortname);
162 if (pid_width > 0)
163 string.printf ("%*.*s ", -pid_width, pid_width, pid_name);
164
165 /* Show whether we are in SingleKey mode. */
166 if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
167 {
168 string.puts (SINGLE_KEY);
169 string.puts (" ");
170 }
171
172 /* Procedure/class name. */
173 if (proc_width > 0)
174 {
175 if (strlen (pname) > proc_width)
176 string.printf ("%s%*.*s* ", PROC_PREFIX,
177 1 - proc_width, proc_width - 1, pname);
178 else
179 string.printf ("%s%*.*s ", PROC_PREFIX,
180 -proc_width, proc_width, pname);
181 }
182
183 if (line_width > 0)
184 string.printf ("%s%*.*s ", LINE_PREFIX,
185 -line_width, line_width, line_buf);
186 if (pc_width > 0)
187 {
188 string.puts (PC_PREFIX);
189 string.puts (pc_buf);
190 }
191
192 if (string.size () < status_size)
193 string.puts (n_spaces (status_size - string.size ()));
194 else if (string.size () > status_size)
195 string.string ().erase (status_size, string.size ());
196
197 return std::move (string.string ());
198 }
199
200 /* Get a printable name for the function at the address. The symbol
201 name is demangled if demangling is turned on. Returns a pointer to
202 a static area holding the result. */
203 static char*
204 tui_get_function_from_frame (struct frame_info *fi)
205 {
206 static char name[256];
207 string_file stream;
208
209 print_address_symbolic (get_frame_arch (fi), get_frame_pc (fi),
210 &stream, demangle, "");
211
212 /* Use simple heuristics to isolate the function name. The symbol
213 can be demangled and we can have function parameters. Remove
214 them because the status line is too short to display them. */
215 const char *d = stream.c_str ();
216 if (*d == '<')
217 d++;
218 strncpy (name, d, sizeof (name) - 1);
219 name[sizeof (name) - 1] = 0;
220
221 char *p = strchr (name, '(');
222 if (!p)
223 p = strchr (name, '>');
224 if (p)
225 *p = 0;
226 p = strchr (name, '+');
227 if (p)
228 *p = 0;
229 return name;
230 }
231
232 void
233 tui_locator_window::rerender ()
234 {
235 if (handle != NULL)
236 {
237 std::string string = tui_make_status_line (this);
238 wmove (handle, 0, 0);
239 /* We ignore the return value from wstandout and wstandend, casting
240 them to void in order to avoid a compiler warning. The warning
241 itself was introduced by a patch to ncurses 5.7 dated 2009-08-29,
242 changing these macro to expand to code that causes the compiler
243 to generate an unused-value warning. */
244 (void) wstandout (handle);
245 waddstr (handle, string.c_str ());
246 wclrtoeol (handle);
247 (void) wstandend (handle);
248 refresh_window ();
249 wmove (handle, 0, 0);
250 }
251 }
252
253 /* See tui-stack.h. */
254
255 void
256 tui_locator_window::set_locator_fullname (const char *fullname)
257 {
258 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
259
260 locator->full_name[0] = 0;
261 strcat_to_buf (locator->full_name, MAX_LOCATOR_ELEMENT_LEN, fullname);
262 rerender ();
263 }
264
265 /* See tui-stack.h. */
266
267 bool
268 tui_locator_window::set_locator_info (struct gdbarch *gdbarch_in,
269 const char *fullname,
270 const char *procname,
271 int lineno,
272 CORE_ADDR addr_in)
273 {
274 bool locator_changed_p = false;
275
276 if (procname == NULL)
277 procname = "";
278
279 if (fullname == NULL)
280 fullname = "";
281
282 locator_changed_p |= strncmp (proc_name, procname,
283 MAX_LOCATOR_ELEMENT_LEN) != 0;
284 locator_changed_p |= lineno != line_no;
285 locator_changed_p |= addr_in != addr;
286 locator_changed_p |= gdbarch_in != gdbarch;
287 locator_changed_p |= strncmp (full_name, fullname,
288 MAX_LOCATOR_ELEMENT_LEN) != 0;
289
290 proc_name[0] = (char) 0;
291 strcat_to_buf (proc_name, MAX_LOCATOR_ELEMENT_LEN, procname);
292 line_no = lineno;
293 addr = addr_in;
294 gdbarch = gdbarch_in;
295 set_locator_fullname (fullname);
296
297 return locator_changed_p;
298 }
299
300 /* Update only the full_name portion of the locator. */
301 void
302 tui_update_locator_fullname (const char *fullname)
303 {
304 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
305
306 locator->set_locator_fullname (fullname);
307 }
308
309 /* Function to print the frame information for the TUI. The windows are
310 refreshed only if frame information has changed since the last refresh.
311
312 Return 1 if frame information has changed (and windows subsequently
313 refreshed), 0 otherwise. */
314
315 int
316 tui_show_frame_info (struct frame_info *fi)
317 {
318 bool locator_changed_p;
319 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
320
321 if (fi)
322 {
323 CORE_ADDR pc;
324
325 symtab_and_line sal = find_frame_sal (fi);
326
327 const char *fullname = nullptr;
328 if (sal.symtab != nullptr)
329 fullname = symtab_to_fullname (sal.symtab);
330
331 if (get_frame_pc_if_available (fi, &pc))
332 locator_changed_p
333 = locator->set_locator_info (get_frame_arch (fi),
334 (sal.symtab == 0
335 ? "??" : fullname),
336 tui_get_function_from_frame (fi),
337 sal.line,
338 pc);
339 else
340 locator_changed_p
341 = locator->set_locator_info (get_frame_arch (fi),
342 "??", _("<unavailable>"), sal.line, 0);
343
344 /* If the locator information has not changed, then frame information has
345 not changed. If frame information has not changed, then the windows'
346 contents will not change. So don't bother refreshing the windows. */
347 if (!locator_changed_p)
348 return 0;
349
350 for (struct tui_source_window_base *win_info : tui_source_windows ())
351 {
352 win_info->maybe_update (fi, sal, locator->line_no, locator->addr);
353 win_info->update_exec_info ();
354 }
355
356 return 1;
357 }
358 else
359 {
360 locator_changed_p
361 = locator->set_locator_info (NULL, NULL, NULL, 0, (CORE_ADDR) 0);
362
363 if (!locator_changed_p)
364 return 0;
365
366 for (struct tui_source_window_base *win_info : tui_source_windows ())
367 {
368 win_info->erase_source_content ();
369 win_info->update_exec_info ();
370 }
371
372 return 1;
373 }
374 }
375
376 void
377 tui_show_locator_content ()
378 {
379 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
380 locator->rerender ();
381 }
382
383 /* Command to update the display with the current execution point. */
384 static void
385 tui_update_command (const char *arg, int from_tty)
386 {
387 execute_command ("frame 0", from_tty);
388 }
389
390 /* Function to initialize gdb commands, for tui window stack
391 manipulation. */
392
393 void
394 _initialize_tui_stack (void)
395 {
396 add_com ("update", class_tui, tui_update_command,
397 _("Update the source window and locator to "
398 "display the current execution point."));
399 }