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