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