xref: /openbsd-src/gnu/usr.bin/binutils/gprof/source.c (revision c074d1c999f3e07019cd5e9a2f190b057ef3b935)
1b55d4692Sfgsch /* source.c - Keep track of source files.
2b55d4692Sfgsch 
3*c074d1c9Sdrahn    Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
4b55d4692Sfgsch 
5b55d4692Sfgsch    This file is part of GNU Binutils.
6b55d4692Sfgsch 
7b55d4692Sfgsch    This program is free software; you can redistribute it and/or modify
8b55d4692Sfgsch    it under the terms of the GNU General Public License as published by
9b55d4692Sfgsch    the Free Software Foundation; either version 2 of the License, or
10b55d4692Sfgsch    (at your option) any later version.
11b55d4692Sfgsch 
12b55d4692Sfgsch    This program is distributed in the hope that it will be useful,
13b55d4692Sfgsch    but WITHOUT ANY WARRANTY; without even the implied warranty of
14b55d4692Sfgsch    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15b55d4692Sfgsch    GNU General Public License for more details.
16b55d4692Sfgsch 
17b55d4692Sfgsch    You should have received a copy of the GNU General Public License
18b55d4692Sfgsch    along with this program; if not, write to the Free Software
19b55d4692Sfgsch    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20b55d4692Sfgsch    02111-1307, USA.  */
21b55d4692Sfgsch 
222159047fSniklas #include "gprof.h"
232159047fSniklas #include "libiberty.h"
24b305b0f1Sespie #include "filenames.h"
252159047fSniklas #include "search_list.h"
262159047fSniklas #include "source.h"
272159047fSniklas 
28b55d4692Sfgsch #define EXT_ANNO "-ann"		/* Postfix of annotated files.  */
292159047fSniklas 
30b55d4692Sfgsch /* Default option values.  */
31*c074d1c9Sdrahn bfd_boolean create_annotation_files = FALSE;
322159047fSniklas 
33b55d4692Sfgsch Search_List src_search_list = {0, 0};
342159047fSniklas Source_File *first_src_file = 0;
352159047fSniklas 
362159047fSniklas 
372159047fSniklas Source_File *
source_file_lookup_path(path)38*c074d1c9Sdrahn source_file_lookup_path (path)
39*c074d1c9Sdrahn      const char *path;
402159047fSniklas {
412159047fSniklas   Source_File *sf;
422159047fSniklas 
432159047fSniklas   for (sf = first_src_file; sf; sf = sf->next)
442159047fSniklas     {
45b305b0f1Sespie       if (FILENAME_CMP (path, sf->name) == 0)
462159047fSniklas 	break;
472159047fSniklas     }
48b55d4692Sfgsch 
492159047fSniklas   if (!sf)
502159047fSniklas     {
51b55d4692Sfgsch       /* Create a new source file descriptor.  */
522159047fSniklas       sf = (Source_File *) xmalloc (sizeof (*sf));
53b55d4692Sfgsch 
542159047fSniklas       memset (sf, 0, sizeof (*sf));
55b55d4692Sfgsch 
564361b62eSniklas       sf->name = xstrdup (path);
572159047fSniklas       sf->next = first_src_file;
582159047fSniklas       first_src_file = sf;
592159047fSniklas     }
60b55d4692Sfgsch 
612159047fSniklas   return sf;
622159047fSniklas }
632159047fSniklas 
642159047fSniklas 
652159047fSniklas Source_File *
source_file_lookup_name(filename)66*c074d1c9Sdrahn source_file_lookup_name (filename)
67*c074d1c9Sdrahn      const char *filename;
682159047fSniklas {
692159047fSniklas   const char *fname;
702159047fSniklas   Source_File *sf;
71b55d4692Sfgsch 
72b55d4692Sfgsch   /* The user cannot know exactly how a filename will be stored in
73b55d4692Sfgsch      the debugging info (e.g., ../include/foo.h
74b55d4692Sfgsch      vs. /usr/include/foo.h).  So we simply compare the filename
75b55d4692Sfgsch      component of a path only.  */
762159047fSniklas   for (sf = first_src_file; sf; sf = sf->next)
772159047fSniklas     {
782159047fSniklas       fname = strrchr (sf->name, '/');
79b55d4692Sfgsch 
802159047fSniklas       if (fname)
812159047fSniklas 	++fname;
822159047fSniklas       else
832159047fSniklas 	fname = sf->name;
84b55d4692Sfgsch 
85b305b0f1Sespie       if (FILENAME_CMP (filename, fname) == 0)
862159047fSniklas 	break;
872159047fSniklas     }
88b55d4692Sfgsch 
892159047fSniklas   return sf;
902159047fSniklas }
912159047fSniklas 
922159047fSniklas 
932159047fSniklas FILE *
annotate_source(sf,max_width,annote,arg)94*c074d1c9Sdrahn annotate_source (sf, max_width, annote, arg)
95*c074d1c9Sdrahn      Source_File *sf;
96*c074d1c9Sdrahn      unsigned int max_width;
97*c074d1c9Sdrahn      void (*annote) PARAMS ((char *, unsigned int, int, void *));
98*c074d1c9Sdrahn      void *arg;
992159047fSniklas {
100*c074d1c9Sdrahn   static bfd_boolean first_file = TRUE;
1012159047fSniklas   int i, line_num, nread;
102*c074d1c9Sdrahn   bfd_boolean new_line;
1032159047fSniklas   char buf[8192];
1042159047fSniklas   char fname[PATH_MAX];
1052159047fSniklas   char *annotation, *name_only;
1062159047fSniklas   FILE *ifp, *ofp;
1072159047fSniklas   Search_List_Elem *sle = src_search_list.head;
1082159047fSniklas 
109b55d4692Sfgsch   /* Open input file.  If open fails, walk along search-list until
110b55d4692Sfgsch      open succeeds or reaching end of list.  */
1112159047fSniklas   strcpy (fname, sf->name);
112b55d4692Sfgsch 
113b305b0f1Sespie   if (IS_ABSOLUTE_PATH (sf->name))
114b55d4692Sfgsch     sle = 0;			/* Don't use search list for absolute paths.  */
115b55d4692Sfgsch 
1162159047fSniklas   name_only = 0;
1172159047fSniklas   while (TRUE)
1182159047fSniklas     {
1192159047fSniklas       DBG (SRCDEBUG, printf ("[annotate_source]: looking for %s, trying %s\n",
1202159047fSniklas 			     sf->name, fname));
121b55d4692Sfgsch 
1222159047fSniklas       ifp = fopen (fname, FOPEN_RB);
1232159047fSniklas       if (ifp)
1242159047fSniklas 	break;
125b55d4692Sfgsch 
1262159047fSniklas       if (!sle && !name_only)
1272159047fSniklas 	{
1282159047fSniklas 	  name_only = strrchr (sf->name, '/');
129b305b0f1Sespie #ifdef HAVE_DOS_BASED_FILE_SYSTEM
130b305b0f1Sespie 	  {
131b305b0f1Sespie 	    char *bslash = strrchr (sf->name, '\\');
132b55d4692Sfgsch 	    if (name_only == NULL || (bslash != NULL && bslash > name_only))
133b305b0f1Sespie 	      name_only = bslash;
134b305b0f1Sespie 	    if (name_only == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
135b305b0f1Sespie 	      name_only = (char *)sf->name + 1;
136b305b0f1Sespie 	  }
137b305b0f1Sespie #endif
1382159047fSniklas 	  if (name_only)
1392159047fSniklas 	    {
140b55d4692Sfgsch 	      /* Try search-list again, but this time with name only.  */
1412159047fSniklas 	      ++name_only;
1422159047fSniklas 	      sle = src_search_list.head;
1432159047fSniklas 	    }
1442159047fSniklas 	}
145b55d4692Sfgsch 
1462159047fSniklas       if (sle)
1472159047fSniklas 	{
1482159047fSniklas 	  strcpy (fname, sle->path);
149b305b0f1Sespie #ifdef HAVE_DOS_BASED_FILE_SYSTEM
150b305b0f1Sespie 	  /* d:foo is not the same thing as d:/foo!  */
151b305b0f1Sespie 	  if (fname[strlen (fname) - 1] == ':')
152b305b0f1Sespie 	    strcat (fname, ".");
153b305b0f1Sespie #endif
1542159047fSniklas 	  strcat (fname, "/");
155b55d4692Sfgsch 
1562159047fSniklas 	  if (name_only)
1572159047fSniklas 	    strcat (fname, name_only);
1582159047fSniklas 	  else
1592159047fSniklas 	    strcat (fname, sf->name);
160b55d4692Sfgsch 
1612159047fSniklas 	  sle = sle->next;
1622159047fSniklas 	}
1632159047fSniklas       else
1642159047fSniklas 	{
1652159047fSniklas 	  if (errno == ENOENT)
166b305b0f1Sespie 	    fprintf (stderr, _("%s: could not locate `%s'\n"),
1672159047fSniklas 		     whoami, sf->name);
1682159047fSniklas 	  else
1692159047fSniklas 	    perror (sf->name);
170b55d4692Sfgsch 
1712159047fSniklas 	  return 0;
1722159047fSniklas 	}
1732159047fSniklas     }
1742159047fSniklas 
1752159047fSniklas   ofp = stdout;
176b55d4692Sfgsch 
1772159047fSniklas   if (create_annotation_files)
1782159047fSniklas     {
179b55d4692Sfgsch       /* Try to create annotated source file.  */
1802159047fSniklas       const char *filename;
1812159047fSniklas 
182b55d4692Sfgsch       /* Create annotation files in the current working directory.  */
1832159047fSniklas       filename = strrchr (sf->name, '/');
184b305b0f1Sespie #ifdef HAVE_DOS_BASED_FILE_SYSTEM
185b305b0f1Sespie 	{
186b305b0f1Sespie 	  char *bslash = strrchr (sf->name, '\\');
187b55d4692Sfgsch 	  if (filename == NULL || (bslash != NULL && bslash > filename))
188b305b0f1Sespie 	    filename = bslash;
189b305b0f1Sespie 	  if (filename == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
190b305b0f1Sespie 	    filename = sf->name + 1;
191b305b0f1Sespie 	}
192b305b0f1Sespie #endif
1932159047fSniklas       if (filename)
1942159047fSniklas 	++filename;
1952159047fSniklas       else
1962159047fSniklas 	filename = sf->name;
1972159047fSniklas 
1982159047fSniklas       strcpy (fname, filename);
1992159047fSniklas       strcat (fname, EXT_ANNO);
200b305b0f1Sespie #ifdef __MSDOS__
201b305b0f1Sespie       {
202b305b0f1Sespie 	/* foo.cpp-ann can overwrite foo.cpp due to silent truncation of
203b305b0f1Sespie 	   file names on 8+3 filesystems.  Their `stat' better be good...  */
204b305b0f1Sespie 	struct stat buf1, buf2;
205b305b0f1Sespie 
206b305b0f1Sespie 	if (stat (filename, &buf1) == 0
207b305b0f1Sespie 	    && stat (fname, &buf2) == 0
208b305b0f1Sespie 	    && buf1.st_ino == buf2.st_ino)
209b305b0f1Sespie 	  {
210b305b0f1Sespie 	    char *dot = strrchr (fname, '.');
211b305b0f1Sespie 
212b305b0f1Sespie 	    if (dot)
213b305b0f1Sespie 	      *dot = '\0';
214b305b0f1Sespie 	    strcat (fname, ".ann");
215b305b0f1Sespie 	  }
216b305b0f1Sespie       }
217b305b0f1Sespie #endif
2182159047fSniklas       ofp = fopen (fname, "w");
219b55d4692Sfgsch 
2202159047fSniklas       if (!ofp)
2212159047fSniklas 	{
2222159047fSniklas 	  perror (fname);
2232159047fSniklas 	  return 0;
2242159047fSniklas 	}
2252159047fSniklas     }
2262159047fSniklas 
227b55d4692Sfgsch   /* Print file names if output goes to stdout
228b55d4692Sfgsch      and there are more than one source file.  */
2292159047fSniklas   if (ofp == stdout)
2302159047fSniklas     {
2312159047fSniklas       if (first_file)
2322159047fSniklas 	first_file = FALSE;
2332159047fSniklas       else
2342159047fSniklas 	fputc ('\n', ofp);
235b55d4692Sfgsch 
2362159047fSniklas       if (first_output)
2372159047fSniklas 	first_output = FALSE;
2382159047fSniklas       else
2392159047fSniklas 	fprintf (ofp, "\f\n");
240b55d4692Sfgsch 
241b305b0f1Sespie       fprintf (ofp, _("*** File %s:\n"), sf->name);
2422159047fSniklas     }
2432159047fSniklas 
2442159047fSniklas   annotation = xmalloc (max_width + 1);
2452159047fSniklas   line_num = 1;
2462159047fSniklas   new_line = TRUE;
247b55d4692Sfgsch 
2482159047fSniklas   while ((nread = fread (buf, 1, sizeof (buf), ifp)) > 0)
2492159047fSniklas     {
2502159047fSniklas       for (i = 0; i < nread; ++i)
2512159047fSniklas 	{
2522159047fSniklas 	  if (new_line)
2532159047fSniklas 	    {
2542159047fSniklas 	      (*annote) (annotation, max_width, line_num, arg);
2552159047fSniklas 	      fputs (annotation, ofp);
2562159047fSniklas 	      ++line_num;
2572159047fSniklas 	      new_line = FALSE;
2582159047fSniklas 	    }
259b55d4692Sfgsch 
2602159047fSniklas 	  new_line = (buf[i] == '\n');
2612159047fSniklas 	  fputc (buf[i], ofp);
2622159047fSniklas 	}
2632159047fSniklas     }
264b55d4692Sfgsch 
2652159047fSniklas   free (annotation);
2662159047fSniklas   return ofp;
2672159047fSniklas }
268