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