1/* TUI display source/assembly window.
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 <ctype.h>
27#include "symtab.h"
28#include "frame.h"
29#include "breakpoint.h"
30#include "value.h"
31#include "source.h"
32
33#include "tui/tui.h"
34#include "tui/tui-data.h"
35#include "tui/tui-stack.h"
36#include "tui/tui-win.h"
37#include "tui/tui-wingeneral.h"
38#include "tui/tui-winsource.h"
39#include "tui/tui-source.h"
40#include "tui/tui-disasm.h"
41
42#include "gdb_string.h"
43#include "gdb_curses.h"
44
45/* Function to display the "main" routine.  */
46void
47tui_display_main (void)
48{
49  if ((tui_source_windows ())->count > 0)
50    {
51      CORE_ADDR addr;
52
53      addr = tui_get_begin_asm_address ();
54      if (addr != (CORE_ADDR) 0)
55	{
56	  struct symtab_and_line sal;
57
58	  tui_update_source_windows_with_addr (addr);
59	  sal = find_pc_line (addr, 0);
60          if (sal.symtab)
61             tui_update_locator_filename (sal.symtab->filename);
62          else
63             tui_update_locator_filename ("??");
64	}
65    }
66}
67
68
69
70/* Function to display source in the source window.  This function
71   initializes the horizontal scroll to 0.  */
72void
73tui_update_source_window (struct tui_win_info * win_info, struct symtab *s,
74			  union tui_line_or_address line_or_addr, int noerror)
75{
76  win_info->detail.source_info.horizontal_offset = 0;
77  tui_update_source_window_as_is (win_info, s, line_or_addr, noerror);
78
79  return;
80}
81
82
83/* Function to display source in the source/asm window.  This function
84   shows the source as specified by the horizontal offset.  */
85void
86tui_update_source_window_as_is (struct tui_win_info * win_info, struct symtab *s,
87				union tui_line_or_address line_or_addr, int noerror)
88{
89  enum tui_status ret;
90
91  if (win_info->generic.type == SRC_WIN)
92    ret = tui_set_source_content (s, line_or_addr.line_no, noerror);
93  else
94    ret = tui_set_disassem_content (line_or_addr.addr);
95
96  if (ret == TUI_FAILURE)
97    {
98      tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
99      tui_clear_exec_info_content (win_info);
100    }
101  else
102    {
103      tui_update_breakpoint_info (win_info, 0);
104      tui_show_source_content (win_info);
105      tui_update_exec_info (win_info);
106      if (win_info->generic.type == SRC_WIN)
107	{
108	  struct symtab_and_line sal;
109
110	  sal.line = line_or_addr.line_no +
111	    (win_info->generic.content_size - 2);
112	  sal.symtab = s;
113	  set_current_source_symtab_and_line (&sal);
114	  /*
115	     ** If the focus was in the asm win, put it in the src
116	     ** win if we don't have a split layout
117	   */
118	  if (tui_win_with_focus () == TUI_DISASM_WIN &&
119	      tui_current_layout () != SRC_DISASSEM_COMMAND)
120	    tui_set_win_focus_to (TUI_SRC_WIN);
121	}
122    }
123
124
125  return;
126}
127
128
129/* Function to ensure that the source and/or disassemly windows
130   reflect the input address.  */
131void
132tui_update_source_windows_with_addr (CORE_ADDR addr)
133{
134  if (addr != 0)
135    {
136      struct symtab_and_line sal;
137      union tui_line_or_address l;
138
139      switch (tui_current_layout ())
140	{
141	case DISASSEM_COMMAND:
142	case DISASSEM_DATA_COMMAND:
143	  tui_show_disassem (addr);
144	  break;
145	case SRC_DISASSEM_COMMAND:
146	  tui_show_disassem_and_update_source (addr);
147	  break;
148	default:
149	  sal = find_pc_line (addr, 0);
150	  l.line_no = sal.line;
151	  tui_show_symtab_source (sal.symtab, l, FALSE);
152	  break;
153	}
154    }
155  else
156    {
157      int i;
158
159      for (i = 0; i < (tui_source_windows ())->count; i++)
160	{
161	  struct tui_win_info * win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
162
163	  tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
164	  tui_clear_exec_info_content (win_info);
165	}
166    }
167}
168
169/* Function to ensure that the source and/or disassemly windows
170   reflect the input address.  */
171void
172tui_update_source_windows_with_line (struct symtab *s, int line)
173{
174  CORE_ADDR pc;
175  union tui_line_or_address l;
176
177  switch (tui_current_layout ())
178    {
179    case DISASSEM_COMMAND:
180    case DISASSEM_DATA_COMMAND:
181      find_line_pc (s, line, &pc);
182      tui_update_source_windows_with_addr (pc);
183      break;
184    default:
185      l.line_no = line;
186      tui_show_symtab_source (s, l, FALSE);
187      if (tui_current_layout () == SRC_DISASSEM_COMMAND)
188	{
189	  find_line_pc (s, line, &pc);
190	  tui_show_disassem (pc);
191	}
192      break;
193    }
194
195  return;
196}
197
198void
199tui_clear_source_content (struct tui_win_info * win_info, int display_prompt)
200{
201  if (win_info != NULL)
202    {
203      int i;
204
205      win_info->generic.content_in_use = FALSE;
206      tui_erase_source_content (win_info, display_prompt);
207      for (i = 0; i < win_info->generic.content_size; i++)
208	{
209	  struct tui_win_element * element =
210	  (struct tui_win_element *) win_info->generic.content[i];
211	  element->which_element.source.has_break = FALSE;
212	  element->which_element.source.is_exec_point = FALSE;
213	}
214    }
215}
216
217
218void
219tui_erase_source_content (struct tui_win_info * win_info, int display_prompt)
220{
221  int x_pos;
222  int half_width = (win_info->generic.width - 2) / 2;
223
224  if (win_info->generic.handle != (WINDOW *) NULL)
225    {
226      werase (win_info->generic.handle);
227      tui_check_and_display_highlight_if_needed (win_info);
228      if (display_prompt == EMPTY_SOURCE_PROMPT)
229	{
230	  char *no_src_str;
231
232	  if (win_info->generic.type == SRC_WIN)
233	    no_src_str = NO_SRC_STRING;
234	  else
235	    no_src_str = NO_DISASSEM_STRING;
236	  if (strlen (no_src_str) >= half_width)
237	    x_pos = 1;
238	  else
239	    x_pos = half_width - strlen (no_src_str);
240	  mvwaddstr (win_info->generic.handle,
241		     (win_info->generic.height / 2),
242		     x_pos,
243		     no_src_str);
244
245	  /* elz: added this function call to set the real contents of
246	     the window to what is on the  screen, so that later calls
247	     to refresh, do display
248	     the correct stuff, and not the old image */
249
250	  tui_set_source_content_nil (win_info, no_src_str);
251	}
252      tui_refresh_win (&win_info->generic);
253    }
254}
255
256
257/* Redraw the complete line of a source or disassembly window.  */
258static void
259tui_show_source_line (struct tui_win_info * win_info, int lineno)
260{
261  struct tui_win_element * line;
262  int x, y;
263
264  line = (struct tui_win_element *) win_info->generic.content[lineno - 1];
265  if (line->which_element.source.is_exec_point)
266    wattron (win_info->generic.handle, A_STANDOUT);
267
268  mvwaddstr (win_info->generic.handle, lineno, 1,
269             line->which_element.source.line);
270  if (line->which_element.source.is_exec_point)
271    wattroff (win_info->generic.handle, A_STANDOUT);
272
273  /* Clear to end of line but stop before the border.  */
274  getyx (win_info->generic.handle, y, x);
275  while (x + 1 < win_info->generic.width)
276    {
277      waddch (win_info->generic.handle, ' ');
278      getyx (win_info->generic.handle, y, x);
279    }
280}
281
282void
283tui_show_source_content (struct tui_win_info * win_info)
284{
285  if (win_info->generic.content_size > 0)
286    {
287      int lineno;
288
289      for (lineno = 1; lineno <= win_info->generic.content_size; lineno++)
290        tui_show_source_line (win_info, lineno);
291    }
292  else
293    tui_erase_source_content (win_info, TRUE);
294
295  tui_check_and_display_highlight_if_needed (win_info);
296  tui_refresh_win (&win_info->generic);
297  win_info->generic.content_in_use = TRUE;
298}
299
300
301/* Scroll the source forward or backward horizontally.  */
302void
303tui_horizontal_source_scroll (struct tui_win_info * win_info,
304			      enum tui_scroll_direction direction,
305			      int num_to_scroll)
306{
307  if (win_info->generic.content != NULL)
308    {
309      int offset;
310      struct symtab *s;
311      struct symtab_and_line cursal = get_current_source_symtab_and_line ();
312
313      if (cursal.symtab == (struct symtab *) NULL)
314	s = find_pc_symtab (get_frame_pc (deprecated_selected_frame));
315      else
316	s = cursal.symtab;
317
318      if (direction == LEFT_SCROLL)
319	offset = win_info->detail.source_info.horizontal_offset + num_to_scroll;
320      else
321	{
322	  if ((offset =
323	     win_info->detail.source_info.horizontal_offset - num_to_scroll) < 0)
324	    offset = 0;
325	}
326      win_info->detail.source_info.horizontal_offset = offset;
327      tui_update_source_window_as_is (win_info, s,
328				      ((struct tui_win_element *)
329				       win_info->generic.content[0])->which_element.source.line_or_addr,
330				      FALSE);
331    }
332
333  return;
334}
335
336
337/* Set or clear the has_break flag in the line whose line is line_no.  */
338void
339tui_set_is_exec_point_at (union tui_line_or_address l, struct tui_win_info * win_info)
340{
341  int changed = 0;
342  int i;
343  tui_win_content content = (tui_win_content) win_info->generic.content;
344
345  i = 0;
346  while (i < win_info->generic.content_size)
347    {
348      int new_state;
349
350      if (content[i]->which_element.source.line_or_addr.addr == l.addr)
351        new_state = TRUE;
352      else
353	new_state = FALSE;
354      if (new_state != content[i]->which_element.source.is_exec_point)
355        {
356          changed++;
357          content[i]->which_element.source.is_exec_point = new_state;
358          tui_show_source_line (win_info, i + 1);
359        }
360      i++;
361    }
362  if (changed)
363    tui_refresh_win (&win_info->generic);
364}
365
366/* Update the execution windows to show the active breakpoints.
367   This is called whenever a breakpoint is inserted, removed or
368   has its state changed.  */
369void
370tui_update_all_breakpoint_info (void)
371{
372  struct tui_list *list = tui_source_windows ();
373  int i;
374
375  for (i = 0; i < list->count; i++)
376    {
377      struct tui_win_info * win = (struct tui_win_info *) list->list[i];
378
379      if (tui_update_breakpoint_info (win, FALSE))
380        {
381          tui_update_exec_info (win);
382        }
383    }
384}
385
386
387/* Scan the source window and the breakpoints to update the
388   has_break information for each line.
389   Returns 1 if something changed and the execution window
390   must be refreshed.  */
391int
392tui_update_breakpoint_info (struct tui_win_info * win, int current_only)
393{
394  int i;
395  int need_refresh = 0;
396  struct tui_source_info * src = &win->detail.source_info;
397
398  for (i = 0; i < win->generic.content_size; i++)
399    {
400      struct breakpoint *bp;
401      extern struct breakpoint *breakpoint_chain;
402      int mode;
403      struct tui_source_element* line;
404
405      line = &((struct tui_win_element *) win->generic.content[i])->which_element.source;
406      if (current_only && !line->is_exec_point)
407         continue;
408
409      /* Scan each breakpoint to see if the current line has something to
410         do with it.  Identify enable/disabled breakpoints as well as
411         those that we already hit.  */
412      mode = 0;
413      for (bp = breakpoint_chain;
414           bp != (struct breakpoint *) NULL;
415           bp = bp->next)
416        {
417          if ((win == TUI_SRC_WIN
418               && bp->source_file
419               && (strcmp (src->filename, bp->source_file) == 0)
420               && bp->line_number == line->line_or_addr.line_no)
421              || (win == TUI_DISASM_WIN
422                  && bp->loc->address == line->line_or_addr.addr))
423            {
424              if (bp->enable_state == bp_disabled)
425                mode |= TUI_BP_DISABLED;
426              else
427                mode |= TUI_BP_ENABLED;
428              if (bp->hit_count)
429                mode |= TUI_BP_HIT;
430              if (bp->cond)
431                mode |= TUI_BP_CONDITIONAL;
432              if (bp->type == bp_hardware_breakpoint)
433                mode |= TUI_BP_HARDWARE;
434            }
435        }
436      if (line->has_break != mode)
437        {
438          line->has_break = mode;
439          need_refresh = 1;
440        }
441    }
442  return need_refresh;
443}
444
445
446/* Function to initialize the content of the execution info window,
447   based upon the input window which is either the source or
448   disassembly window.  */
449enum tui_status
450tui_set_exec_info_content (struct tui_win_info * win_info)
451{
452  enum tui_status ret = TUI_SUCCESS;
453
454  if (win_info->detail.source_info.execution_info != (struct tui_gen_win_info *) NULL)
455    {
456      struct tui_gen_win_info * exec_info_ptr = win_info->detail.source_info.execution_info;
457
458      if (exec_info_ptr->content == NULL)
459	exec_info_ptr->content =
460	  (void **) tui_alloc_content (win_info->generic.height,
461					 exec_info_ptr->type);
462      if (exec_info_ptr->content != NULL)
463	{
464	  int i;
465
466          tui_update_breakpoint_info (win_info, 1);
467	  for (i = 0; i < win_info->generic.content_size; i++)
468	    {
469	      struct tui_win_element * element;
470	      struct tui_win_element * src_element;
471              int mode;
472
473	      element = (struct tui_win_element *) exec_info_ptr->content[i];
474	      src_element = (struct tui_win_element *) win_info->generic.content[i];
475
476              memset(element->which_element.simple_string, ' ',
477                     sizeof(element->which_element.simple_string));
478              element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0;
479
480	      /* Now update the exec info content based upon the state
481                 of each line as indicated by the source content.  */
482              mode = src_element->which_element.source.has_break;
483              if (mode & TUI_BP_HIT)
484                element->which_element.simple_string[TUI_BP_HIT_POS] =
485                  (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
486              else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
487                element->which_element.simple_string[TUI_BP_HIT_POS] =
488                  (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
489
490              if (mode & TUI_BP_ENABLED)
491                element->which_element.simple_string[TUI_BP_BREAK_POS] = '+';
492              else if (mode & TUI_BP_DISABLED)
493                element->which_element.simple_string[TUI_BP_BREAK_POS] = '-';
494
495              if (src_element->which_element.source.is_exec_point)
496                element->which_element.simple_string[TUI_EXEC_POS] = '>';
497	    }
498	  exec_info_ptr->content_size = win_info->generic.content_size;
499	}
500      else
501	ret = TUI_FAILURE;
502    }
503
504  return ret;
505}
506
507
508void
509tui_show_exec_info_content (struct tui_win_info * win_info)
510{
511  struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info;
512  int cur_line;
513
514  werase (exec_info->handle);
515  tui_refresh_win (exec_info);
516  for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
517    mvwaddstr (exec_info->handle,
518	       cur_line,
519	       0,
520	       ((struct tui_win_element *)
521		exec_info->content[cur_line - 1])->which_element.simple_string);
522  tui_refresh_win (exec_info);
523  exec_info->content_in_use = TRUE;
524}
525
526
527void
528tui_erase_exec_info_content (struct tui_win_info * win_info)
529{
530  struct tui_gen_win_info * exec_info = win_info->detail.source_info.execution_info;
531
532  werase (exec_info->handle);
533  tui_refresh_win (exec_info);
534}
535
536void
537tui_clear_exec_info_content (struct tui_win_info * win_info)
538{
539  win_info->detail.source_info.execution_info->content_in_use = FALSE;
540  tui_erase_exec_info_content (win_info);
541
542  return;
543}
544
545/* Function to update the execution info window.  */
546void
547tui_update_exec_info (struct tui_win_info * win_info)
548{
549  tui_set_exec_info_content (win_info);
550  tui_show_exec_info_content (win_info);
551}
552
553enum tui_status
554tui_alloc_source_buffer (struct tui_win_info *win_info)
555{
556  char *src_line_buf;
557  int i, line_width, max_lines;
558  enum tui_status ret = TUI_FAILURE;
559
560  max_lines = win_info->generic.height;	/* less the highlight box */
561  line_width = win_info->generic.width - 1;
562  /*
563     ** Allocate the buffer for the source lines.  Do this only once since they
564     ** will be re-used for all source displays.  The only other time this will
565     ** be done is when a window's size changes.
566   */
567  if (win_info->generic.content == NULL)
568    {
569      src_line_buf = (char *) xmalloc ((max_lines * line_width) * sizeof (char));
570      if (src_line_buf == (char *) NULL)
571	fputs_unfiltered (
572	   "Unable to Allocate Memory for Source or Disassembly Display.\n",
573			   gdb_stderr);
574      else
575	{
576	  /* allocate the content list */
577	  if ((win_info->generic.content =
578	  (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL)
579	    {
580	      xfree (src_line_buf);
581	      src_line_buf = (char *) NULL;
582	      fputs_unfiltered (
583				 "Unable to Allocate Memory for Source or Disassembly Display.\n",
584				 gdb_stderr);
585	    }
586	}
587      for (i = 0; i < max_lines; i++)
588	((struct tui_win_element *)
589	 win_info->generic.content[i])->which_element.source.line =
590	  src_line_buf + (line_width * i);
591      ret = TUI_SUCCESS;
592    }
593  else
594    ret = TUI_SUCCESS;
595
596  return ret;
597}
598
599
600/* Answer whether the a particular line number or address is displayed
601   in the current source window.  */
602int
603tui_line_is_displayed (int line, struct tui_win_info * win_info,
604		       int check_threshold)
605{
606  int is_displayed = FALSE;
607  int i, threshold;
608
609  if (check_threshold)
610    threshold = SCROLL_THRESHOLD;
611  else
612    threshold = 0;
613  i = 0;
614  while (i < win_info->generic.content_size - threshold && !is_displayed)
615    {
616      is_displayed = (((struct tui_win_element *)
617		      win_info->generic.content[i])->which_element.source.line_or_addr.line_no
618		     == (int) line);
619      i++;
620    }
621
622  return is_displayed;
623}
624
625
626/* Answer whether the a particular line number or address is displayed
627   in the current source window.  */
628int
629tui_addr_is_displayed (CORE_ADDR addr, struct tui_win_info * win_info,
630		    int check_threshold)
631{
632  int is_displayed = FALSE;
633  int i, threshold;
634
635  if (check_threshold)
636    threshold = SCROLL_THRESHOLD;
637  else
638    threshold = 0;
639  i = 0;
640  while (i < win_info->generic.content_size - threshold && !is_displayed)
641    {
642      is_displayed = (((struct tui_win_element *)
643		      win_info->generic.content[i])->which_element.source.line_or_addr.addr
644		     == addr);
645      i++;
646    }
647
648  return is_displayed;
649}
650
651
652/*****************************************
653** STATIC LOCAL FUNCTIONS               **
654******************************************/
655