1 1.1 christos /* source.c - Keep track of source files. 2 1.1 christos 3 1.10 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.10 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.8 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.8 christos static bool first_file = true; 97 1.1 christos int i, line_num, nread; 98 1.8 christos bool new_line; 99 1.1 christos char buf[8192]; 100 1.8 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.8 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.8 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.8 christos if (fname != sf->name) 120 1.8 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.8 christos fname = xmalloc (strlen (sle->path) + 3 147 1.8 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.8 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.8 christos if (!dot) 214 1.8 christos dot = fname + strlen (filename); 215 1.8 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.8 christos free (fname); 225 1.1 christos return 0; 226 1.1 christos } 227 1.8 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.8 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.8 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.8 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.3 christos fclose (ifp); 269 1.1 christos return ofp; 270 1.1 christos } 271