xref: /openbsd/gnu/usr.bin/binutils/gprof/source.c (revision 133306f0)
1 /*
2  * Keeps track of source files.
3  */
4 #include "gprof.h"
5 #include "libiberty.h"
6 #include "filenames.h"
7 #include "search_list.h"
8 #include "source.h"
9 
10 #define EXT_ANNO "-ann"		/* postfix of annotated files */
11 
12 /*
13  * Default option values:
14  */
15 bool create_annotation_files = FALSE;
16 
17 Search_List src_search_list =
18 {0, 0};
19 Source_File *first_src_file = 0;
20 
21 
22 Source_File *
23 DEFUN (source_file_lookup_path, (path), const char *path)
24 {
25   Source_File *sf;
26 
27   for (sf = first_src_file; sf; sf = sf->next)
28     {
29       if (FILENAME_CMP (path, sf->name) == 0)
30 	{
31 	  break;
32 	}
33     }
34   if (!sf)
35     {
36       /* create a new source file descriptor: */
37 
38       sf = (Source_File *) xmalloc (sizeof (*sf));
39       memset (sf, 0, sizeof (*sf));
40       sf->name = xstrdup (path);
41       sf->next = first_src_file;
42       first_src_file = sf;
43     }
44   return sf;
45 }
46 
47 
48 Source_File *
49 DEFUN (source_file_lookup_name, (filename), const char *filename)
50 {
51   const char *fname;
52   Source_File *sf;
53   /*
54    * The user cannot know exactly how a filename will be stored in
55    * the debugging info (e.g., ../include/foo.h
56    * vs. /usr/include/foo.h).  So we simply compare the filename
57    * component of a path only:
58    */
59   for (sf = first_src_file; sf; sf = sf->next)
60     {
61       fname = strrchr (sf->name, '/');
62       if (fname)
63 	{
64 	  ++fname;
65 	}
66       else
67 	{
68 	  fname = sf->name;
69 	}
70       if (FILENAME_CMP (filename, fname) == 0)
71 	{
72 	  break;
73 	}
74     }
75   return sf;
76 }
77 
78 
79 FILE *
80 DEFUN (annotate_source, (sf, max_width, annote, arg),
81        Source_File * sf AND int max_width
82        AND void (*annote) PARAMS ((char *buf, int w, int l, void *arg))
83        AND void *arg)
84 {
85   static bool first_file = TRUE;
86   int i, line_num, nread;
87   bool new_line;
88   char buf[8192];
89   char fname[PATH_MAX];
90   char *annotation, *name_only;
91   FILE *ifp, *ofp;
92   Search_List_Elem *sle = src_search_list.head;
93 
94   /*
95    * Open input file.  If open fails, walk along search-list until
96    * open succeeds or reaching end of list:
97    */
98   strcpy (fname, sf->name);
99   if (IS_ABSOLUTE_PATH (sf->name))
100     {
101       sle = 0;			/* don't use search list for absolute paths */
102     }
103   name_only = 0;
104   while (TRUE)
105     {
106       DBG (SRCDEBUG, printf ("[annotate_source]: looking for %s, trying %s\n",
107 			     sf->name, fname));
108       ifp = fopen (fname, FOPEN_RB);
109       if (ifp)
110 	{
111 	  break;
112 	}
113       if (!sle && !name_only)
114 	{
115 	  name_only = strrchr (sf->name, '/');
116 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
117 	  {
118 	    char *bslash = strrchr (sf->name, '\\');
119 	    if (bslash > name_only)
120 	      name_only = bslash;
121 	    if (name_only == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
122 	      name_only = (char *)sf->name + 1;
123 	  }
124 #endif
125 	  if (name_only)
126 	    {
127 	      /* try search-list again, but this time with name only: */
128 	      ++name_only;
129 	      sle = src_search_list.head;
130 	    }
131 	}
132       if (sle)
133 	{
134 	  strcpy (fname, sle->path);
135 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
136 	  /* d:foo is not the same thing as d:/foo!  */
137 	  if (fname[strlen (fname) - 1] == ':')
138 	    strcat (fname, ".");
139 #endif
140 	  strcat (fname, "/");
141 	  if (name_only)
142 	    {
143 	      strcat (fname, name_only);
144 	    }
145 	  else
146 	    {
147 	      strcat (fname, sf->name);
148 	    }
149 	  sle = sle->next;
150 	}
151       else
152 	{
153 	  if (errno == ENOENT)
154 	    {
155 	      fprintf (stderr, _("%s: could not locate `%s'\n"),
156 		       whoami, sf->name);
157 	    }
158 	  else
159 	    {
160 	      perror (sf->name);
161 	    }
162 	  return 0;
163 	}
164     }
165 
166   ofp = stdout;
167   if (create_annotation_files)
168     {
169       /* try to create annotated source file: */
170       const char *filename;
171 
172       /* create annotation files in the current working directory: */
173       filename = strrchr (sf->name, '/');
174 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
175 	{
176 	  char *bslash = strrchr (sf->name, '\\');
177 	  if (bslash > filename)
178 	    filename = bslash;
179 	  if (filename == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
180 	    filename = sf->name + 1;
181 	}
182 #endif
183       if (filename)
184 	{
185 	  ++filename;
186 	}
187       else
188 	{
189 	  filename = sf->name;
190 	}
191 
192       strcpy (fname, filename);
193       strcat (fname, EXT_ANNO);
194 #ifdef __MSDOS__
195       {
196 	/* foo.cpp-ann can overwrite foo.cpp due to silent truncation of
197 	   file names on 8+3 filesystems.  Their `stat' better be good...  */
198 	struct stat buf1, buf2;
199 
200 	if (stat (filename, &buf1) == 0
201 	    && stat (fname, &buf2) == 0
202 	    && buf1.st_ino == buf2.st_ino)
203 	  {
204 	    char *dot = strrchr (fname, '.');
205 
206 	    if (dot)
207 	      *dot = '\0';
208 	    strcat (fname, ".ann");
209 	  }
210       }
211 #endif
212       ofp = fopen (fname, "w");
213       if (!ofp)
214 	{
215 	  perror (fname);
216 	  return 0;
217 	}
218     }
219 
220   /*
221    * Print file names if output goes to stdout and there are
222    * more than one source file:
223    */
224   if (ofp == stdout)
225     {
226       if (first_file)
227 	{
228 	  first_file = FALSE;
229 	}
230       else
231 	{
232 	  fputc ('\n', ofp);
233 	}
234       if (first_output)
235 	{
236 	  first_output = FALSE;
237 	}
238       else
239 	{
240 	  fprintf (ofp, "\f\n");
241 	}
242       fprintf (ofp, _("*** File %s:\n"), sf->name);
243     }
244 
245   annotation = xmalloc (max_width + 1);
246   line_num = 1;
247   new_line = TRUE;
248   while ((nread = fread (buf, 1, sizeof (buf), ifp)) > 0)
249     {
250       for (i = 0; i < nread; ++i)
251 	{
252 	  if (new_line)
253 	    {
254 	      (*annote) (annotation, max_width, line_num, arg);
255 	      fputs (annotation, ofp);
256 	      ++line_num;
257 	      new_line = FALSE;
258 	    }
259 	  new_line = (buf[i] == '\n');
260 	  fputc (buf[i], ofp);
261 	}
262     }
263   free (annotation);
264   return ofp;
265 }
266