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