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