Lots of changes from David Mosberger-Tang; see ChangeLog and NOTES for details:
[external/binutils.git] / gprof / source.c
1 /*
2  * Keeps track of source files.
3  */
4 #include "gprof.h"
5 #include "libiberty.h"
6 #include "search_list.h"
7 #include "source.h"
8
9 #define EXT_ANNO "-ann"         /* postfix of annotated files */
10
11 /*
12  * Default option values:
13  */
14 bool create_annotation_files = FALSE;
15
16 Search_List src_search_list = {0, 0};
17 Source_File *first_src_file = 0;
18
19
20 Source_File*
21 DEFUN(source_file_lookup_path, (path), const char *path)
22 {
23     Source_File *sf;
24
25     for (sf = first_src_file; sf; sf = sf->next) {
26         if (strcmp(path, sf->name) == 0) {
27             break;
28         } /* if */
29     } /* for */
30     if (!sf) {
31         /* create a new source file descriptor: */
32
33         sf = (Source_File*) xmalloc(sizeof(*sf));
34         memset(sf, 0, sizeof(*sf));
35         sf->name = strdup(path);
36         sf->next = first_src_file;
37         first_src_file = sf;
38     } /* if */
39     return sf;
40 } /* source_file_lookup_path */
41
42
43 Source_File*
44 DEFUN(source_file_lookup_name, (filename), const char *filename)
45 {
46     const char *fname;
47     Source_File *sf;
48     /*
49      * The user cannot know exactly how a filename will be stored in
50      * the debugging info (e.g., ../include/foo.h
51      * vs. /usr/include/foo.h).  So we simply compare the filename
52      * component of a path only:
53      */
54     for (sf = first_src_file; sf; sf = sf->next) {
55         fname = strrchr(sf->name, '/');
56         if (fname) {
57             ++fname;
58         } else {
59             fname = sf->name;
60         } /* if */
61         if (strcmp(filename, fname) == 0) {
62             break;
63         } /* if */
64     } /* for */
65     return sf;
66 } /* source_file_lookup_name */
67
68
69 FILE*
70 DEFUN(annotate_source, (sf, max_width, annote, arg),
71       Source_File *sf AND int max_width
72       AND void (*annote) PARAMS((char *buf, int w, int l, void *arg))
73       AND void *arg)
74 {
75     static bool first_file = TRUE;
76     int i, line_num, nread;
77     bool new_line;
78     char buf[8192];
79     char fname[PATH_MAX];
80     char *annotation, *name_only;
81     FILE *ifp, *ofp;
82     Search_List_Elem *sle = src_search_list.head;
83
84     /*
85      * Open input file.  If open fails, walk along search-list until
86      * open succeeds or reaching end of list:
87      */
88     strcpy(fname, sf->name);
89     if (sf->name[0] == '/') {
90         sle = 0;        /* don't use search list for absolute paths */
91     } /* if */
92     name_only = 0;
93     while (TRUE) {
94         DBG(SRCDEBUG, printf("[annotate_source]: looking for %s, trying %s\n",
95                              sf->name, fname));
96         ifp = fopen(fname, FOPEN_RB);
97         if (ifp) {
98             break;
99         } /* if */
100         if (!sle && !name_only) {
101             name_only = strrchr(sf->name, '/');
102             if (name_only) {
103                 /* try search-list again, but this time with name only: */
104                 ++name_only;
105                 sle = src_search_list.head;
106             } /* if */
107         } /* if */
108         if (sle) {
109             strcpy(fname, sle->path);
110             strcat(fname, "/");
111             if (name_only) {
112                 strcat(fname, name_only);
113             } else {
114                 strcat(fname, sf->name);
115             } /* if */
116             sle = sle->next;
117         } else {
118             if (errno == ENOENT) {
119                 fprintf(stderr, "%s: could not locate `%s'\n",
120                         whoami, sf->name);
121             } else {
122                 perror(sf->name);
123             } /* if */
124             return 0;
125         } /* if */
126     } /* while */
127
128     ofp = stdout;
129     if (create_annotation_files) {
130         /* try to create annotated source file: */
131         const char *filename;
132
133         /* create annotation files in the current working directory: */
134         filename = strrchr(sf->name, '/');
135         if (filename) {
136             ++filename;
137         } else {
138             filename = sf->name;
139         } /* if */
140
141         strcpy(fname, filename);
142         strcat(fname, EXT_ANNO);
143         ofp = fopen(fname, "w");
144         if (!ofp) {
145             perror(fname);
146             return 0;
147         } /* if */
148     } /* if */
149
150     /*
151      * Print file names if output goes to stdout and there are
152      * more than one source file:
153      */
154     if (ofp == stdout) {
155         if (first_file) {
156             first_file = FALSE;
157         } else {
158             fputc('\n', ofp);
159         } /* if */
160         if (first_output) {
161             first_output = FALSE;
162         } else {
163             fprintf(ofp, "\f\n");
164         } /* if */
165         fprintf(ofp, "*** File %s:\n", sf->name);
166     } /* if */
167
168     annotation = xmalloc(max_width + 1);
169     line_num = 1;
170     new_line = TRUE;
171     while ((nread = fread(buf, 1, sizeof(buf), ifp)) > 0) {
172         for (i = 0; i < nread; ++i) {
173             if (new_line) {
174                 (*annote)(annotation, max_width, line_num, arg);
175                 fputs(annotation, ofp);
176                 ++line_num; new_line = FALSE;
177             } /* if */
178             new_line = (buf[i] == '\n');
179             fputc(buf[i], ofp);
180         } /* for */
181     } /* while */
182     free(annotation);
183     return ofp;
184 } /* annotate_source */
185
186                         /*** end of source.c ***/