You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
6.1 KiB
C

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/* source.c - Keep track of source files.
Copyright (C) 2000-2022 Free Software Foundation, Inc.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "gprof.h"
#include "libiberty.h"
#include "filenames.h"
#include "search_list.h"
#include "source.h"
#define EXT_ANNO "-ann" /* Postfix of annotated files. */
/* Default option values. */
bool create_annotation_files = false;
Search_List src_search_list = {0, 0};
Source_File *first_src_file = 0;
Source_File *
source_file_lookup_path (const char *path)
{
Source_File *sf;
for (sf = first_src_file; sf; sf = sf->next)
{
if (FILENAME_CMP (path, sf->name) == 0)
break;
}
if (!sf)
{
/* Create a new source file descriptor. */
sf = (Source_File *) xmalloc (sizeof (*sf));
memset (sf, 0, sizeof (*sf));
sf->name = xstrdup (path);
sf->next = first_src_file;
first_src_file = sf;
}
return sf;
}
Source_File *
source_file_lookup_name (const char *filename)
{
const char *fname;
Source_File *sf;
/* The user cannot know exactly how a filename will be stored in
the debugging info (e.g., ../include/foo.h
vs. /usr/include/foo.h). So we simply compare the filename
component of a path only. */
for (sf = first_src_file; sf; sf = sf->next)
{
fname = strrchr (sf->name, '/');
if (fname)
++fname;
else
fname = sf->name;
if (FILENAME_CMP (filename, fname) == 0)
break;
}
return sf;
}
FILE *
annotate_source (Source_File *sf, unsigned int max_width,
void (*annote) (char *, unsigned int, int, void *),
void *arg)
{
static bool first_file = true;
int i, line_num, nread;
bool new_line;
char buf[8192];
char *fname;
char *annotation, *name_only;
FILE *ifp, *ofp;
Search_List_Elem *sle = src_search_list.head;
/* Open input file. If open fails, walk along search-list until
open succeeds or reaching end of list. */
fname = (char *) sf->name;
if (IS_ABSOLUTE_PATH (sf->name))
sle = 0; /* Don't use search list for absolute paths. */
name_only = 0;
while (true)
{
DBG (SRCDEBUG, printf ("[annotate_source]: looking for %s, trying %s\n",
sf->name, fname));
ifp = fopen (fname, FOPEN_RB);
if (fname != sf->name)
free (fname);
if (ifp)
break;
if (!sle && !name_only)
{
name_only = strrchr (sf->name, '/');
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
{
char *bslash = strrchr (sf->name, '\\');
if (name_only == NULL || (bslash != NULL && bslash > name_only))
name_only = bslash;
if (name_only == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
name_only = (char *)sf->name + 1;
}
#endif
if (name_only)
{
/* Try search-list again, but this time with name only. */
++name_only;
sle = src_search_list.head;
}
}
if (sle)
{
fname = xmalloc (strlen (sle->path) + 3
+ strlen (name_only ? name_only : sf->name));
strcpy (fname, sle->path);
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
/* d:foo is not the same thing as d:/foo! */
if (fname[strlen (fname) - 1] == ':')
strcat (fname, ".");
#endif
strcat (fname, "/");
if (name_only)
strcat (fname, name_only);
else
strcat (fname, sf->name);
sle = sle->next;
}
else
{
if (errno == ENOENT)
fprintf (stderr, _("%s: could not locate `%s'\n"),
whoami, sf->name);
else
perror (sf->name);
return 0;
}
}
ofp = stdout;
if (create_annotation_files)
{
/* Try to create annotated source file. */
const char *filename;
/* Create annotation files in the current working directory. */
filename = strrchr (sf->name, '/');
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
{
char *bslash = strrchr (sf->name, '\\');
if (filename == NULL || (bslash != NULL && bslash > filename))
filename = bslash;
if (filename == NULL && sf->name[0] != '\0' && sf->name[1] == ':')
filename = sf->name + 1;
}
#endif
if (filename)
++filename;
else
filename = sf->name;
fname = xmalloc (strlen (filename) + strlen (EXT_ANNO) + 1);
strcpy (fname, filename);
strcat (fname, EXT_ANNO);
#ifdef __MSDOS__
{
/* foo.cpp-ann can overwrite foo.cpp due to silent truncation of
file names on 8+3 filesystems. Their `stat' better be good... */
struct stat buf1, buf2;
if (stat (filename, &buf1) == 0
&& stat (fname, &buf2) == 0
&& buf1.st_ino == buf2.st_ino)
{
char *dot = strrchr (fname, '.');
if (!dot)
dot = fname + strlen (filename);
strcpy (dot, ".ann");
}
}
#endif
ofp = fopen (fname, "w");
if (!ofp)
{
perror (fname);
free (fname);
return 0;
}
free (fname);
}
/* Print file names if output goes to stdout
and there are more than one source file. */
if (ofp == stdout)
{
if (first_file)
first_file = false;
else
fputc ('\n', ofp);
if (first_output)
first_output = false;
else
fprintf (ofp, "\f\n");
fprintf (ofp, _("*** File %s:\n"), sf->name);
}
annotation = (char *) xmalloc (max_width + 1);
line_num = 1;
new_line = true;
while ((nread = fread (buf, 1, sizeof (buf), ifp)) > 0)
{
for (i = 0; i < nread; ++i)
{
if (new_line)
{
(*annote) (annotation, max_width, line_num, arg);
fputs (annotation, ofp);
++line_num;
}
new_line = (buf[i] == '\n');
fputc (buf[i], ofp);
}
}
free (annotation);
fclose (ifp);
return ofp;
}