blob: c95eacde7e3cd129095feb57e0e17d644f90a30e [file] [log] [blame]
Neil Boothd82fc102001-08-02 23:03:31 +00001/* Map logical line numbers to (source file, line number) pairs.
Kazu Hiratad9221e012004-01-21 20:40:04 +00002 Copyright (C) 2001, 2003, 2004
Neil Boothd82fc102001-08-02 23:03:31 +00003 Free Software Foundation, Inc.
4
5This program is free software; you can redistribute it and/or modify it
6under the terms of the GNU General Public License as published by the
7Free Software Foundation; either version 2, or (at your option) any
8later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
Kelley Cook200031d2005-06-29 02:34:39 +000017Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Neil Boothd82fc102001-08-02 23:03:31 +000018
19 In other words, you are welcome to use, share and improve this program.
20 You are forbidden to forbid anyone else to use, share and improve
21 what you give them. Help stamp out software-hoarding! */
22
23#include "config.h"
24#include "system.h"
25#include "line-map.h"
26
Neil Boothe2b98532003-06-20 05:51:13 +000027static void trace_include (const struct line_maps *, const struct line_map *);
Neil Booth59930192001-08-21 21:17:48 +000028
Neil Boothd82fc102001-08-02 23:03:31 +000029/* Initialize a line map set. */
30
31void
Zack Weinberga2f7be92003-07-22 16:24:53 +000032linemap_init (struct line_maps *set)
Neil Boothd82fc102001-08-02 23:03:31 +000033{
Per Bothner9132fbb2004-01-20 05:17:48 +000034 set->maps = NULL;
Neil Boothd82fc102001-08-02 23:03:31 +000035 set->allocated = 0;
36 set->used = 0;
Neil Boothfde84342001-08-06 21:07:41 +000037 set->last_listed = -1;
Neil Booth59930192001-08-21 21:17:48 +000038 set->trace_includes = false;
Neil Boothd8693c62001-08-21 23:05:12 +000039 set->depth = 0;
Per Bothner9132fbb2004-01-20 05:17:48 +000040 set->cache = 0;
Per Bothner12f9df42004-02-11 07:29:30 -080041 set->highest_location = 0;
Per Bothner500bee02004-04-22 19:22:27 -070042 set->highest_line = 0;
Per Bothner12f9df42004-02-11 07:29:30 -080043 set->max_column_hint = 0;
Neil Boothd82fc102001-08-02 23:03:31 +000044}
45
Kazu Hirata9ac97462004-02-16 14:20:10 +000046/* Check for and warn about line_maps entered but not exited. */
Per Bothner12f9df42004-02-11 07:29:30 -080047
48void
49linemap_check_files_exited (struct line_maps *set)
50{
51 struct line_map *map;
52 /* Depending upon whether we are handling preprocessed input or
53 not, this can be a user error or an ICE. */
54 for (map = &set->maps[set->used - 1]; ! MAIN_FILE_P (map);
55 map = INCLUDED_FROM (set, map))
56 fprintf (stderr, "line-map.c: file \"%s\" entered but not left\n",
57 map->to_file);
58}
59
Neil Boothd82fc102001-08-02 23:03:31 +000060/* Free a line map set. */
61
Neil Boothfde84342001-08-06 21:07:41 +000062void
Zack Weinberga2f7be92003-07-22 16:24:53 +000063linemap_free (struct line_maps *set)
Neil Boothd82fc102001-08-02 23:03:31 +000064{
65 if (set->maps)
Neil Boothfde84342001-08-06 21:07:41 +000066 {
Per Bothner12f9df42004-02-11 07:29:30 -080067 linemap_check_files_exited (set);
Neil Booth47d89cf2001-08-11 07:33:39 +000068
Neil Boothfde84342001-08-06 21:07:41 +000069 free (set->maps);
70 }
Neil Boothd82fc102001-08-02 23:03:31 +000071}
72
73/* Add a mapping of logical source line to physical source file and
Geoffrey Keating90744642003-07-30 06:43:33 +000074 line number.
75
76 The text pointed to by TO_FILE must have a lifetime
77 at least as long as the final call to lookup_line (). An empty
78 TO_FILE means standard input. If reason is LC_LEAVE, and
79 TO_FILE is NULL, then TO_FILE, TO_LINE and SYSP are given their
80 natural values considering the file we are returning to.
Neil Boothd82fc102001-08-02 23:03:31 +000081
82 FROM_LINE should be monotonic increasing across calls to this
Geoffrey Keating90744642003-07-30 06:43:33 +000083 function. A call to this function can relocate the previous set of
Per Bothner12f9df42004-02-11 07:29:30 -080084 A call to this function can relocate the previous set of
Geoffrey Keating90744642003-07-30 06:43:33 +000085 maps, so any stored line_map pointers should not be used. */
Neil Boothd82fc102001-08-02 23:03:31 +000086
Neil Booth47d89cf2001-08-11 07:33:39 +000087const struct line_map *
Zack Weinberga2f7be92003-07-22 16:24:53 +000088linemap_add (struct line_maps *set, enum lc_reason reason,
Per Bothner12f9df42004-02-11 07:29:30 -080089 unsigned int sysp, const char *to_file, unsigned int to_line)
Neil Boothd82fc102001-08-02 23:03:31 +000090{
91 struct line_map *map;
Per Bothner12f9df42004-02-11 07:29:30 -080092 source_location start_location = set->highest_location + 1;
Neil Boothd82fc102001-08-02 23:03:31 +000093
Per Bothner12f9df42004-02-11 07:29:30 -080094 if (set->used && start_location < set->maps[set->used - 1].start_location)
Neil Boothd82fc102001-08-02 23:03:31 +000095 abort ();
96
97 if (set->used == set->allocated)
98 {
99 set->allocated = 2 * set->allocated + 256;
Gabriel Dos Reisc3f829c2005-05-28 15:52:48 +0000100 set->maps = XRESIZEVEC (struct line_map, set->maps, set->allocated);
Neil Boothd82fc102001-08-02 23:03:31 +0000101 }
102
Per Bothner9132fbb2004-01-20 05:17:48 +0000103 map = &set->maps[set->used];
Neil Boothd82fc102001-08-02 23:03:31 +0000104
Geoffrey Keating90744642003-07-30 06:43:33 +0000105 if (to_file && *to_file == '\0')
106 to_file = "<stdin>";
107
Neil Boothfde84342001-08-06 21:07:41 +0000108 /* If we don't keep our line maps consistent, we can easily
109 segfault. Don't rely on the client to do it for us. */
Neil Boothd8693c62001-08-21 23:05:12 +0000110 if (set->depth == 0)
Neil Boothfde84342001-08-06 21:07:41 +0000111 reason = LC_ENTER;
112 else if (reason == LC_LEAVE)
113 {
Neil Booth47d89cf2001-08-11 07:33:39 +0000114 struct line_map *from;
115 bool error;
116
117 if (MAIN_FILE_P (map - 1))
Neil Boothfde84342001-08-06 21:07:41 +0000118 {
Per Bothnerb3147022003-07-22 23:11:34 +0000119 if (to_file == NULL)
120 {
121 set->depth--;
Per Bothnerb3147022003-07-22 23:11:34 +0000122 return NULL;
123 }
124 error = true;
125 reason = LC_RENAME;
126 from = map - 1;
Neil Booth47d89cf2001-08-11 07:33:39 +0000127 }
128 else
129 {
130 from = INCLUDED_FROM (set, map - 1);
131 error = to_file && strcmp (from->to_file, to_file);
132 }
133
134 /* Depending upon whether we are handling preprocessed input or
135 not, this can be a user error or an ICE. */
136 if (error)
137 fprintf (stderr, "line-map.c: file \"%s\" left but not entered\n",
138 to_file);
139
140 /* A TO_FILE of NULL is special - we use the natural values. */
141 if (error || to_file == NULL)
142 {
143 to_file = from->to_file;
Per Bothner12f9df42004-02-11 07:29:30 -0800144 to_line = SOURCE_LINE (from, from[1].start_location);
Neil Booth47d89cf2001-08-11 07:33:39 +0000145 sysp = from->sysp;
Neil Boothfde84342001-08-06 21:07:41 +0000146 }
147 }
148
Neil Booth47d89cf2001-08-11 07:33:39 +0000149 map->reason = reason;
150 map->sysp = sysp;
Per Bothner12f9df42004-02-11 07:29:30 -0800151 map->start_location = start_location;
Neil Booth47d89cf2001-08-11 07:33:39 +0000152 map->to_file = to_file;
153 map->to_line = to_line;
Per Bothner9132fbb2004-01-20 05:17:48 +0000154 set->cache = set->used++;
Per Bothner12f9df42004-02-11 07:29:30 -0800155 map->column_bits = 0;
156 set->highest_location = start_location;
Per Bothner500bee02004-04-22 19:22:27 -0700157 set->highest_line = start_location;
Per Bothner12f9df42004-02-11 07:29:30 -0800158 set->max_column_hint = 0;
Neil Booth47d89cf2001-08-11 07:33:39 +0000159
Neil Boothfde84342001-08-06 21:07:41 +0000160 if (reason == LC_ENTER)
Neil Boothd8693c62001-08-21 23:05:12 +0000161 {
Per Bothner8826ff02003-03-20 16:43:19 +0000162 map->included_from = set->depth == 0 ? -1 : (int) (set->used - 2);
Neil Boothd8693c62001-08-21 23:05:12 +0000163 set->depth++;
Neil Boothd8693c62001-08-21 23:05:12 +0000164 if (set->trace_includes)
165 trace_include (set, map);
166 }
Neil Boothd82fc102001-08-02 23:03:31 +0000167 else if (reason == LC_RENAME)
168 map->included_from = map[-1].included_from;
169 else if (reason == LC_LEAVE)
Neil Boothd8693c62001-08-21 23:05:12 +0000170 {
171 set->depth--;
172 map->included_from = INCLUDED_FROM (set, map - 1)->included_from;
173 }
Neil Booth59930192001-08-21 21:17:48 +0000174
Neil Boothd82fc102001-08-02 23:03:31 +0000175 return map;
176}
177
Per Bothner12f9df42004-02-11 07:29:30 -0800178source_location
179linemap_line_start (struct line_maps *set, unsigned int to_line,
180 unsigned int max_column_hint)
181{
182 struct line_map *map = &set->maps[set->used - 1];
183 source_location highest = set->highest_location;
184 source_location r;
Per Bothner500bee02004-04-22 19:22:27 -0700185 unsigned int last_line = SOURCE_LINE (map, set->highest_line);
Per Bothner12f9df42004-02-11 07:29:30 -0800186 int line_delta = to_line - last_line;
187 bool add_map = false;
188 if (line_delta < 0
189 || (line_delta > 10 && line_delta * map->column_bits > 1000)
190 || (max_column_hint >= (1U << map->column_bits))
191 || (max_column_hint <= 80 && map->column_bits >= 10))
192 {
193 add_map = true;
194 }
195 else
196 max_column_hint = set->max_column_hint;
197 if (add_map)
198 {
199 int column_bits;
Per Bothner500bee02004-04-22 19:22:27 -0700200 if (max_column_hint > 100000 || highest > 0xC0000000)
Per Bothner12f9df42004-02-11 07:29:30 -0800201 {
Per Bothnerc1fc5042005-04-21 10:08:27 -0700202 /* If the column number is ridiculous or we've allocated a huge
203 number of source_locations, give up on column numbers. */
Per Bothner12f9df42004-02-11 07:29:30 -0800204 max_column_hint = 0;
205 if (highest >0xF0000000)
206 return 0;
207 column_bits = 0;
208 }
209 else
210 {
211 column_bits = 7;
212 while (max_column_hint >= (1U << column_bits))
213 column_bits++;
214 max_column_hint = 1U << column_bits;
215 }
Per Bothnerc1fc5042005-04-21 10:08:27 -0700216 /* Allocate the new line_map. However, if the current map only has a
217 single line we can sometimes just increase its column_bits instead. */
Per Bothner12f9df42004-02-11 07:29:30 -0800218 if (line_delta < 0
219 || last_line != map->to_line
220 || SOURCE_COLUMN (map, highest) >= (1U << column_bits))
221 map = (struct line_map*) linemap_add (set, LC_RENAME, map->sysp,
222 map->to_file, to_line);
223 map->column_bits = column_bits;
Per Bothnerc1fc5042005-04-21 10:08:27 -0700224 r = map->start_location + ((to_line - map->to_line) << column_bits);
Per Bothner12f9df42004-02-11 07:29:30 -0800225 }
226 else
227 r = highest - SOURCE_COLUMN (map, highest)
228 + (line_delta << map->column_bits);
Per Bothner500bee02004-04-22 19:22:27 -0700229 set->highest_line = r;
Per Bothner12f9df42004-02-11 07:29:30 -0800230 if (r > set->highest_location)
231 set->highest_location = r;
232 set->max_column_hint = max_column_hint;
233 return r;
234}
235
Per Bothner500bee02004-04-22 19:22:27 -0700236source_location
237linemap_position_for_column (struct line_maps *set, unsigned int to_column)
238{
239 source_location r = set->highest_line;
240 if (to_column >= set->max_column_hint)
241 {
242 if (r >= 0xC000000 || to_column > 100000)
243 {
244 /* Running low on source_locations - disable column numbers. */
245 return r;
246 }
247 else
248 {
249 struct line_map *map = &set->maps[set->used - 1];
250 r = linemap_line_start (set, SOURCE_LINE (map, r), to_column + 50);
251 }
252 }
253 r = r + to_column;
254 if (r >= set->highest_location)
255 set->highest_location = r;
256 return r;
257}
258
Neil Booth6604e6f2001-08-05 21:31:30 +0000259/* Given a logical line, returns the map from which the corresponding
260 (source file, line) pair can be deduced. Since the set is built
261 chronologically, the logical lines are monotonic increasing, and so
262 the list is sorted and we can use a binary search. */
Neil Boothd82fc102001-08-02 23:03:31 +0000263
Neil Booth47d89cf2001-08-11 07:33:39 +0000264const struct line_map *
Per Bothner7d40b452003-12-05 12:52:39 -0800265linemap_lookup (struct line_maps *set, source_location line)
Neil Boothd82fc102001-08-02 23:03:31 +0000266{
Per Bothner9132fbb2004-01-20 05:17:48 +0000267 unsigned int md, mn, mx;
268 const struct line_map *cached;
Neil Boothd82fc102001-08-02 23:03:31 +0000269
Per Bothner9132fbb2004-01-20 05:17:48 +0000270 mn = set->cache;
271 mx = set->used;
272
273 cached = &set->maps[mn];
Kazu Hirata9ac97462004-02-16 14:20:10 +0000274 /* We should get a segfault if no line_maps have been added yet. */
Per Bothner12f9df42004-02-11 07:29:30 -0800275 if (line >= cached->start_location)
Per Bothner9132fbb2004-01-20 05:17:48 +0000276 {
Per Bothner12f9df42004-02-11 07:29:30 -0800277 if (mn + 1 == mx || line < cached[1].start_location)
Per Bothner9132fbb2004-01-20 05:17:48 +0000278 return cached;
279 }
280 else
281 {
282 mx = mn;
283 mn = 0;
284 }
Neil Boothd82fc102001-08-02 23:03:31 +0000285
286 while (mx - mn > 1)
287 {
288 md = (mn + mx) / 2;
Per Bothner12f9df42004-02-11 07:29:30 -0800289 if (set->maps[md].start_location > line)
Neil Boothd82fc102001-08-02 23:03:31 +0000290 mx = md;
291 else
292 mn = md;
293 }
294
Per Bothner9132fbb2004-01-20 05:17:48 +0000295 set->cache = mn;
Neil Boothd82fc102001-08-02 23:03:31 +0000296 return &set->maps[mn];
297}
Neil Boothfde84342001-08-06 21:07:41 +0000298
299/* Print the file names and line numbers of the #include commands
300 which led to the map MAP, if any, to stderr. Nothing is output if
301 the most recently listed stack is the same as the current one. */
302
303void
Zack Weinberga2f7be92003-07-22 16:24:53 +0000304linemap_print_containing_files (struct line_maps *set,
305 const struct line_map *map)
Neil Boothfde84342001-08-06 21:07:41 +0000306{
307 if (MAIN_FILE_P (map) || set->last_listed == map->included_from)
308 return;
309
310 set->last_listed = map->included_from;
311 map = INCLUDED_FROM (set, map);
312
313 fprintf (stderr, _("In file included from %s:%u"),
314 map->to_file, LAST_SOURCE_LINE (map));
315
316 while (! MAIN_FILE_P (map))
317 {
318 map = INCLUDED_FROM (set, map);
319 /* Translators note: this message is used in conjunction
320 with "In file included from %s:%ld" and some other
321 tricks. We want something like this:
322
323 | In file included from sys/select.h:123,
324 | from sys/types.h:234,
325 | from userfile.c:31:
326 | bits/select.h:45: <error message here>
327
328 with all the "from"s lined up.
329 The trailing comma is at the beginning of this message,
330 and the trailing colon is not translated. */
331 fprintf (stderr, _(",\n from %s:%u"),
332 map->to_file, LAST_SOURCE_LINE (map));
333 }
334
335 fputs (":\n", stderr);
336}
Neil Booth59930192001-08-21 21:17:48 +0000337
338/* Print an include trace, for e.g. the -H option of the preprocessor. */
339
340static void
Neil Boothe2b98532003-06-20 05:51:13 +0000341trace_include (const struct line_maps *set, const struct line_map *map)
Neil Booth59930192001-08-21 21:17:48 +0000342{
Neil Boothd8693c62001-08-21 23:05:12 +0000343 unsigned int i = set->depth;
Neil Booth59930192001-08-21 21:17:48 +0000344
Neil Boothd8693c62001-08-21 23:05:12 +0000345 while (--i)
Neil Booth59930192001-08-21 21:17:48 +0000346 putc ('.', stderr);
347 fprintf (stderr, " %s\n", map->to_file);
348}