2000-06-07 Philippe De Muyter <phdm@macqel.be>
[external/binutils.git] / gprof / source.c
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 }