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