xref: /openbsd-src/gnu/usr.bin/binutils/gdb/tui/tui-source.c (revision b725ae7711052a2233e31a66fefb8a752c388d7a)
1*b725ae77Skettenis /* TUI display source window.
2*b725ae77Skettenis 
3*b725ae77Skettenis    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
4*b725ae77Skettenis    Foundation, Inc.
5*b725ae77Skettenis 
6*b725ae77Skettenis    Contributed by Hewlett-Packard Company.
7*b725ae77Skettenis 
8*b725ae77Skettenis    This file is part of GDB.
9*b725ae77Skettenis 
10*b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
11*b725ae77Skettenis    it under the terms of the GNU General Public License as published by
12*b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
13*b725ae77Skettenis    (at your option) any later version.
14*b725ae77Skettenis 
15*b725ae77Skettenis    This program is distributed in the hope that it will be useful,
16*b725ae77Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
17*b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*b725ae77Skettenis    GNU General Public License for more details.
19*b725ae77Skettenis 
20*b725ae77Skettenis    You should have received a copy of the GNU General Public License
21*b725ae77Skettenis    along with this program; if not, write to the Free Software
22*b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
23*b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
24*b725ae77Skettenis 
25*b725ae77Skettenis #include "defs.h"
26*b725ae77Skettenis #include <ctype.h>
27*b725ae77Skettenis #include "symtab.h"
28*b725ae77Skettenis #include "frame.h"
29*b725ae77Skettenis #include "breakpoint.h"
30*b725ae77Skettenis #include "source.h"
31*b725ae77Skettenis #include "symtab.h"
32*b725ae77Skettenis 
33*b725ae77Skettenis #include "tui/tui.h"
34*b725ae77Skettenis #include "tui/tui-data.h"
35*b725ae77Skettenis #include "tui/tui-stack.h"
36*b725ae77Skettenis #include "tui/tui-winsource.h"
37*b725ae77Skettenis #include "tui/tui-source.h"
38*b725ae77Skettenis 
39*b725ae77Skettenis #include "gdb_string.h"
40*b725ae77Skettenis #include "gdb_curses.h"
41*b725ae77Skettenis 
42*b725ae77Skettenis /* Function to display source in the source window.  */
43*b725ae77Skettenis enum tui_status
tui_set_source_content(struct symtab * s,int line_no,int noerror)44*b725ae77Skettenis tui_set_source_content (struct symtab *s, int line_no, int noerror)
45*b725ae77Skettenis {
46*b725ae77Skettenis   enum tui_status ret = TUI_FAILURE;
47*b725ae77Skettenis 
48*b725ae77Skettenis   if (s != (struct symtab *) NULL && s->filename != (char *) NULL)
49*b725ae77Skettenis     {
50*b725ae77Skettenis       FILE *stream;
51*b725ae77Skettenis       int i, desc, c, line_width, nlines;
52*b725ae77Skettenis       char *src_line = 0;
53*b725ae77Skettenis 
54*b725ae77Skettenis       if ((ret = tui_alloc_source_buffer (TUI_SRC_WIN)) == TUI_SUCCESS)
55*b725ae77Skettenis 	{
56*b725ae77Skettenis 	  line_width = TUI_SRC_WIN->generic.width - 1;
57*b725ae77Skettenis 	  /* Take hilite (window border) into account, when calculating
58*b725ae77Skettenis 	     the number of lines  */
59*b725ae77Skettenis 	  nlines = (line_no + (TUI_SRC_WIN->generic.height - 2)) - line_no;
60*b725ae77Skettenis 	  desc = open_source_file (s);
61*b725ae77Skettenis 	  if (desc < 0)
62*b725ae77Skettenis 	    {
63*b725ae77Skettenis 	      if (!noerror)
64*b725ae77Skettenis 		{
65*b725ae77Skettenis 		  char *name = alloca (strlen (s->filename) + 100);
66*b725ae77Skettenis 		  sprintf (name, "%s:%d", s->filename, line_no);
67*b725ae77Skettenis 		  print_sys_errmsg (name, errno);
68*b725ae77Skettenis 		}
69*b725ae77Skettenis 	      ret = TUI_FAILURE;
70*b725ae77Skettenis 	    }
71*b725ae77Skettenis 	  else
72*b725ae77Skettenis 	    {
73*b725ae77Skettenis 	      if (s->line_charpos == 0)
74*b725ae77Skettenis 		find_source_lines (s, desc);
75*b725ae77Skettenis 
76*b725ae77Skettenis 	      if (line_no < 1 || line_no > s->nlines)
77*b725ae77Skettenis 		{
78*b725ae77Skettenis 		  close (desc);
79*b725ae77Skettenis 		  printf_unfiltered (
80*b725ae77Skettenis 			  "Line number %d out of range; %s has %d lines.\n",
81*b725ae77Skettenis 				      line_no, s->filename, s->nlines);
82*b725ae77Skettenis 		}
83*b725ae77Skettenis 	      else if (lseek (desc, s->line_charpos[line_no - 1], 0) < 0)
84*b725ae77Skettenis 		{
85*b725ae77Skettenis 		  close (desc);
86*b725ae77Skettenis 		  perror_with_name (s->filename);
87*b725ae77Skettenis 		}
88*b725ae77Skettenis 	      else
89*b725ae77Skettenis 		{
90*b725ae77Skettenis 		  int offset, cur_line_no, cur_line, cur_len, threshold;
91*b725ae77Skettenis 		  struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
92*b725ae77Skettenis                   struct tui_source_info * src = &TUI_SRC_WIN->detail.source_info;
93*b725ae77Skettenis 
94*b725ae77Skettenis                   if (TUI_SRC_WIN->generic.title)
95*b725ae77Skettenis                     xfree (TUI_SRC_WIN->generic.title);
96*b725ae77Skettenis                   TUI_SRC_WIN->generic.title = xstrdup (s->filename);
97*b725ae77Skettenis 
98*b725ae77Skettenis                   if (src->filename)
99*b725ae77Skettenis                     xfree (src->filename);
100*b725ae77Skettenis                   src->filename = xstrdup (s->filename);
101*b725ae77Skettenis 
102*b725ae77Skettenis 		  /* Determine the threshold for the length of the line
103*b725ae77Skettenis                      and the offset to start the display.  */
104*b725ae77Skettenis 		  offset = src->horizontal_offset;
105*b725ae77Skettenis 		  threshold = (line_width - 1) + offset;
106*b725ae77Skettenis 		  stream = fdopen (desc, FOPEN_RT);
107*b725ae77Skettenis 		  clearerr (stream);
108*b725ae77Skettenis 		  cur_line = 0;
109*b725ae77Skettenis 		  cur_line_no = src->start_line_or_addr.line_no = line_no;
110*b725ae77Skettenis 		  if (offset > 0)
111*b725ae77Skettenis 		    src_line = (char *) xmalloc (
112*b725ae77Skettenis 					   (threshold + 1) * sizeof (char));
113*b725ae77Skettenis 		  while (cur_line < nlines)
114*b725ae77Skettenis 		    {
115*b725ae77Skettenis 		      struct tui_win_element * element = (struct tui_win_element *)
116*b725ae77Skettenis 		      TUI_SRC_WIN->generic.content[cur_line];
117*b725ae77Skettenis 
118*b725ae77Skettenis 		      /* get the first character in the line */
119*b725ae77Skettenis 		      c = fgetc (stream);
120*b725ae77Skettenis 
121*b725ae77Skettenis 		      if (offset == 0)
122*b725ae77Skettenis 			src_line = ((struct tui_win_element *)
123*b725ae77Skettenis 				   TUI_SRC_WIN->generic.content[
124*b725ae77Skettenis 					cur_line])->which_element.source.line;
125*b725ae77Skettenis 		      /* Init the line with the line number */
126*b725ae77Skettenis 		      sprintf (src_line, "%-6d", cur_line_no);
127*b725ae77Skettenis 		      cur_len = strlen (src_line);
128*b725ae77Skettenis 		      i = cur_len -
129*b725ae77Skettenis 			((cur_len / tui_default_tab_len ()) * tui_default_tab_len ());
130*b725ae77Skettenis 		      while (i < tui_default_tab_len ())
131*b725ae77Skettenis 			{
132*b725ae77Skettenis 			  src_line[cur_len] = ' ';
133*b725ae77Skettenis 			  i++;
134*b725ae77Skettenis 			  cur_len++;
135*b725ae77Skettenis 			}
136*b725ae77Skettenis 		      src_line[cur_len] = (char) 0;
137*b725ae77Skettenis 
138*b725ae77Skettenis 		      /* Set whether element is the execution point and
139*b725ae77Skettenis 		         whether there is a break point on it.  */
140*b725ae77Skettenis 		      element->which_element.source.line_or_addr.line_no =
141*b725ae77Skettenis 			cur_line_no;
142*b725ae77Skettenis 		      element->which_element.source.is_exec_point =
143*b725ae77Skettenis 			(strcmp (((struct tui_win_element *)
144*b725ae77Skettenis 			locator->content[0])->which_element.locator.file_name,
145*b725ae77Skettenis 				 s->filename) == 0
146*b725ae77Skettenis 			 && cur_line_no == ((struct tui_win_element *)
147*b725ae77Skettenis 			 locator->content[0])->which_element.locator.line_no);
148*b725ae77Skettenis 		      if (c != EOF)
149*b725ae77Skettenis 			{
150*b725ae77Skettenis 			  i = strlen (src_line) - 1;
151*b725ae77Skettenis 			  do
152*b725ae77Skettenis 			    {
153*b725ae77Skettenis 			      if ((c != '\n') &&
154*b725ae77Skettenis 				  (c != '\r') && (++i < threshold))
155*b725ae77Skettenis 				{
156*b725ae77Skettenis 				  if (c < 040 && c != '\t')
157*b725ae77Skettenis 				    {
158*b725ae77Skettenis 				      src_line[i++] = '^';
159*b725ae77Skettenis 				      src_line[i] = c + 0100;
160*b725ae77Skettenis 				    }
161*b725ae77Skettenis 				  else if (c == 0177)
162*b725ae77Skettenis 				    {
163*b725ae77Skettenis 				      src_line[i++] = '^';
164*b725ae77Skettenis 				      src_line[i] = '?';
165*b725ae77Skettenis 				    }
166*b725ae77Skettenis 				  else
167*b725ae77Skettenis 				    {	/* Store the charcter in the line
168*b725ae77Skettenis 					   buffer.  If it is a tab, then
169*b725ae77Skettenis 					   translate to the correct number of
170*b725ae77Skettenis 					   chars so we don't overwrite our
171*b725ae77Skettenis 					   buffer.  */
172*b725ae77Skettenis 				      if (c == '\t')
173*b725ae77Skettenis 					{
174*b725ae77Skettenis 					  int j, max_tab_len = tui_default_tab_len ();
175*b725ae77Skettenis 
176*b725ae77Skettenis 					  for (j = i - (
177*b725ae77Skettenis 					       (i / max_tab_len) * max_tab_len);
178*b725ae77Skettenis 					       ((j < max_tab_len) &&
179*b725ae77Skettenis 						i < threshold);
180*b725ae77Skettenis 					       i++, j++)
181*b725ae77Skettenis 					    src_line[i] = ' ';
182*b725ae77Skettenis 					  i--;
183*b725ae77Skettenis 					}
184*b725ae77Skettenis 				      else
185*b725ae77Skettenis 					src_line[i] = c;
186*b725ae77Skettenis 				    }
187*b725ae77Skettenis 				  src_line[i + 1] = 0;
188*b725ae77Skettenis 				}
189*b725ae77Skettenis 			      else
190*b725ae77Skettenis 				{	/* If we have not reached EOL, then eat
191*b725ae77Skettenis                                            chars until we do  */
192*b725ae77Skettenis 				  while (c != EOF && c != '\n' && c != '\r')
193*b725ae77Skettenis 				    c = fgetc (stream);
194*b725ae77Skettenis 				}
195*b725ae77Skettenis 			    }
196*b725ae77Skettenis 			  while (c != EOF && c != '\n' && c != '\r' &&
197*b725ae77Skettenis 				 i < threshold && (c = fgetc (stream)));
198*b725ae77Skettenis 			}
199*b725ae77Skettenis 		      /* Now copy the line taking the offset into account */
200*b725ae77Skettenis 		      if (strlen (src_line) > offset)
201*b725ae77Skettenis 			strcpy (((struct tui_win_element *) TUI_SRC_WIN->generic.content[
202*b725ae77Skettenis 					cur_line])->which_element.source.line,
203*b725ae77Skettenis 				&src_line[offset]);
204*b725ae77Skettenis 		      else
205*b725ae77Skettenis 			((struct tui_win_element *)
206*b725ae77Skettenis 			 TUI_SRC_WIN->generic.content[
207*b725ae77Skettenis 			  cur_line])->which_element.source.line[0] = (char) 0;
208*b725ae77Skettenis 		      cur_line++;
209*b725ae77Skettenis 		      cur_line_no++;
210*b725ae77Skettenis 		    }
211*b725ae77Skettenis 		  if (offset > 0)
212*b725ae77Skettenis 		    xfree (src_line);
213*b725ae77Skettenis 		  fclose (stream);
214*b725ae77Skettenis 		  TUI_SRC_WIN->generic.content_size = nlines;
215*b725ae77Skettenis 		  ret = TUI_SUCCESS;
216*b725ae77Skettenis 		}
217*b725ae77Skettenis 	    }
218*b725ae77Skettenis 	}
219*b725ae77Skettenis     }
220*b725ae77Skettenis   return ret;
221*b725ae77Skettenis }
222*b725ae77Skettenis 
223*b725ae77Skettenis 
224*b725ae77Skettenis /* elz: this function sets the contents of the source window to empty
225*b725ae77Skettenis    except for a line in the middle with a warning message about the
226*b725ae77Skettenis    source not being available. This function is called by
227*b725ae77Skettenis    tui_erase_source_contents(), which in turn is invoked when the
228*b725ae77Skettenis    source files cannot be accessed.  */
229*b725ae77Skettenis 
230*b725ae77Skettenis void
tui_set_source_content_nil(struct tui_win_info * win_info,char * warning_string)231*b725ae77Skettenis tui_set_source_content_nil (struct tui_win_info * win_info, char *warning_string)
232*b725ae77Skettenis {
233*b725ae77Skettenis   int line_width;
234*b725ae77Skettenis   int n_lines;
235*b725ae77Skettenis   int curr_line = 0;
236*b725ae77Skettenis 
237*b725ae77Skettenis   line_width = win_info->generic.width - 1;
238*b725ae77Skettenis   n_lines = win_info->generic.height - 2;
239*b725ae77Skettenis 
240*b725ae77Skettenis   /* set to empty each line in the window, except for the one
241*b725ae77Skettenis      which contains the message */
242*b725ae77Skettenis   while (curr_line < win_info->generic.content_size)
243*b725ae77Skettenis     {
244*b725ae77Skettenis       /* set the information related to each displayed line
245*b725ae77Skettenis          to null: i.e. the line number is 0, there is no bp,
246*b725ae77Skettenis          it is not where the program is stopped */
247*b725ae77Skettenis 
248*b725ae77Skettenis       struct tui_win_element * element =
249*b725ae77Skettenis       (struct tui_win_element *) win_info->generic.content[curr_line];
250*b725ae77Skettenis       element->which_element.source.line_or_addr.line_no = 0;
251*b725ae77Skettenis       element->which_element.source.is_exec_point = FALSE;
252*b725ae77Skettenis       element->which_element.source.has_break = FALSE;
253*b725ae77Skettenis 
254*b725ae77Skettenis       /* set the contents of the line to blank */
255*b725ae77Skettenis       element->which_element.source.line[0] = (char) 0;
256*b725ae77Skettenis 
257*b725ae77Skettenis       /* if the current line is in the middle of the screen, then we
258*b725ae77Skettenis          want to display the 'no source available' message in it.
259*b725ae77Skettenis          Note: the 'weird' arithmetic with the line width and height
260*b725ae77Skettenis          comes from the function tui_erase_source_content(). We need
261*b725ae77Skettenis          to keep the screen and the window's actual contents in synch.  */
262*b725ae77Skettenis 
263*b725ae77Skettenis       if (curr_line == (n_lines / 2 + 1))
264*b725ae77Skettenis 	{
265*b725ae77Skettenis 	  int i;
266*b725ae77Skettenis 	  int xpos;
267*b725ae77Skettenis 	  int warning_length = strlen (warning_string);
268*b725ae77Skettenis 	  char *src_line;
269*b725ae77Skettenis 
270*b725ae77Skettenis 	  src_line = element->which_element.source.line;
271*b725ae77Skettenis 
272*b725ae77Skettenis 	  if (warning_length >= ((line_width - 1) / 2))
273*b725ae77Skettenis 	    xpos = 1;
274*b725ae77Skettenis 	  else
275*b725ae77Skettenis 	    xpos = (line_width - 1) / 2 - warning_length;
276*b725ae77Skettenis 
277*b725ae77Skettenis 	  for (i = 0; i < xpos; i++)
278*b725ae77Skettenis 	    src_line[i] = ' ';
279*b725ae77Skettenis 
280*b725ae77Skettenis 	  sprintf (src_line + i, "%s", warning_string);
281*b725ae77Skettenis 
282*b725ae77Skettenis 	  for (i = xpos + warning_length; i < line_width; i++)
283*b725ae77Skettenis 	    src_line[i] = ' ';
284*b725ae77Skettenis 
285*b725ae77Skettenis 	  src_line[i] = '\n';
286*b725ae77Skettenis 
287*b725ae77Skettenis 	}			/* end if */
288*b725ae77Skettenis 
289*b725ae77Skettenis       curr_line++;
290*b725ae77Skettenis 
291*b725ae77Skettenis     }				/* end while */
292*b725ae77Skettenis }
293*b725ae77Skettenis 
294*b725ae77Skettenis 
295*b725ae77Skettenis /* Function to display source in the source window.  This function
296*b725ae77Skettenis    initializes the horizontal scroll to 0.  */
297*b725ae77Skettenis void
tui_show_symtab_source(struct symtab * s,union tui_line_or_address line,int noerror)298*b725ae77Skettenis tui_show_symtab_source (struct symtab *s, union tui_line_or_address line, int noerror)
299*b725ae77Skettenis {
300*b725ae77Skettenis   TUI_SRC_WIN->detail.source_info.horizontal_offset = 0;
301*b725ae77Skettenis   tui_update_source_window_as_is (TUI_SRC_WIN, s, line, noerror);
302*b725ae77Skettenis }
303*b725ae77Skettenis 
304*b725ae77Skettenis 
305*b725ae77Skettenis /* Answer whether the source is currently displayed in the source
306*b725ae77Skettenis    window.  */
307*b725ae77Skettenis int
tui_source_is_displayed(char * fname)308*b725ae77Skettenis tui_source_is_displayed (char *fname)
309*b725ae77Skettenis {
310*b725ae77Skettenis   return (TUI_SRC_WIN->generic.content_in_use &&
311*b725ae77Skettenis 	  (strcmp (((struct tui_win_element *) (tui_locator_win_info_ptr ())->
312*b725ae77Skettenis 		  content[0])->which_element.locator.file_name, fname) == 0));
313*b725ae77Skettenis }
314*b725ae77Skettenis 
315*b725ae77Skettenis 
316*b725ae77Skettenis /* Scroll the source forward or backward vertically.  */
317*b725ae77Skettenis void
tui_vertical_source_scroll(enum tui_scroll_direction scroll_direction,int num_to_scroll)318*b725ae77Skettenis tui_vertical_source_scroll (enum tui_scroll_direction scroll_direction,
319*b725ae77Skettenis 			    int num_to_scroll)
320*b725ae77Skettenis {
321*b725ae77Skettenis   if (TUI_SRC_WIN->generic.content != NULL)
322*b725ae77Skettenis     {
323*b725ae77Skettenis       union tui_line_or_address l;
324*b725ae77Skettenis       struct symtab *s;
325*b725ae77Skettenis       tui_win_content content = (tui_win_content) TUI_SRC_WIN->generic.content;
326*b725ae77Skettenis       struct symtab_and_line cursal = get_current_source_symtab_and_line ();
327*b725ae77Skettenis 
328*b725ae77Skettenis       if (cursal.symtab == (struct symtab *) NULL)
329*b725ae77Skettenis 	s = find_pc_symtab (get_frame_pc (deprecated_selected_frame));
330*b725ae77Skettenis       else
331*b725ae77Skettenis 	s = cursal.symtab;
332*b725ae77Skettenis 
333*b725ae77Skettenis       if (scroll_direction == FORWARD_SCROLL)
334*b725ae77Skettenis 	{
335*b725ae77Skettenis 	  l.line_no = content[0]->which_element.source.line_or_addr.line_no +
336*b725ae77Skettenis 	    num_to_scroll;
337*b725ae77Skettenis 	  if (l.line_no > s->nlines)
338*b725ae77Skettenis 	    /*line = s->nlines - win_info->generic.content_size + 1; */
339*b725ae77Skettenis 	    /*elz: fix for dts 23398 */
340*b725ae77Skettenis 	    l.line_no = content[0]->which_element.source.line_or_addr.line_no;
341*b725ae77Skettenis 	}
342*b725ae77Skettenis       else
343*b725ae77Skettenis 	{
344*b725ae77Skettenis 	  l.line_no = content[0]->which_element.source.line_or_addr.line_no -
345*b725ae77Skettenis 	    num_to_scroll;
346*b725ae77Skettenis 	  if (l.line_no <= 0)
347*b725ae77Skettenis 	    l.line_no = 1;
348*b725ae77Skettenis 	}
349*b725ae77Skettenis 
350*b725ae77Skettenis       print_source_lines (s, l.line_no, l.line_no + 1, 0);
351*b725ae77Skettenis     }
352*b725ae77Skettenis }
353