1 /* Diagnostic subroutines for printing source-code
2 Copyright (C) 1999-2015 Free Software Foundation, Inc.
3 Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
27 #include "backtrace.h"
28 #include "diagnostic.h"
29 #include "diagnostic-color.h"
35 #ifdef GWINSZ_IN_SYS_IOCTL
36 # include <sys/ioctl.h>
39 /* If LINE is longer than MAX_WIDTH, and COLUMN is not smaller than
40 MAX_WIDTH by some margin, then adjust the start of the line such
41 that the COLUMN is smaller than MAX_WIDTH minus the margin. The
42 margin is either CARET_LINE_MARGIN characters or the difference
43 between the column and the length of the line, whatever is smaller.
44 The length of LINE is given by LINE_WIDTH. */
46 adjust_line (const char *line
, int line_width
,
47 int max_width
, int *column_p
)
49 int right_margin
= CARET_LINE_MARGIN
;
50 int column
= *column_p
;
52 gcc_checking_assert (line_width
>= column
);
53 right_margin
= MIN (line_width
- column
, right_margin
);
54 right_margin
= max_width
- right_margin
;
55 if (line_width
>= max_width
&& column
> right_margin
)
57 line
+= column
- right_margin
;
58 *column_p
= right_margin
;
63 /* Print the physical source line corresponding to the location of
64 this diagnostic, and a caret indicating the precise column. This
65 function only prints two caret characters if the two locations
66 given by DIAGNOSTIC are on the same line according to
67 diagnostic_same_line(). */
69 diagnostic_show_locus (diagnostic_context
* context
,
70 const diagnostic_info
*diagnostic
)
72 if (!context
->show_caret
73 || diagnostic_location (diagnostic
, 0) <= BUILTINS_LOCATION
74 || diagnostic_location (diagnostic
, 0) == context
->last_location
)
77 context
->last_location
= diagnostic_location (diagnostic
, 0);
78 expanded_location s0
= diagnostic_expand_location (diagnostic
, 0);
79 expanded_location s1
= { };
80 /* Zero-initialized. This is checked later by diagnostic_print_caret_line. */
82 if (diagnostic_location (diagnostic
, 1) > BUILTINS_LOCATION
)
83 s1
= diagnostic_expand_location (diagnostic
, 1);
85 diagnostic_print_caret_line (context
, s0
, s1
,
86 context
->caret_chars
[0],
87 context
->caret_chars
[1]);
90 /* Print (part) of the source line given by xloc1 with caret1 pointing
91 at the column. If xloc2.column != 0 and it fits within the same
92 line as xloc1 according to diagnostic_same_line (), then caret2 is
93 printed at xloc2.colum. Otherwise, the caller has to set up things
94 to print a second caret line for xloc2. */
96 diagnostic_print_caret_line (diagnostic_context
* context
,
97 expanded_location xloc1
,
98 expanded_location xloc2
,
99 char caret1
, char caret2
)
101 if (!diagnostic_same_line (context
, xloc1
, xloc2
))
102 /* This will mean ignore xloc2. */
104 else if (xloc1
.column
== xloc2
.column
)
107 int cmax
= MAX (xloc1
.column
, xloc2
.column
);
109 const char *line
= location_get_source_line (xloc1
.file
, xloc1
.line
,
111 if (line
== NULL
|| cmax
> line_width
)
114 /* Center the interesting part of the source line to fit in
115 max_width, and adjust all columns accordingly. */
116 int max_width
= context
->caret_max_width
;
117 int offset
= (int) cmax
;
118 line
= adjust_line (line
, line_width
, max_width
, &offset
);
121 xloc1
.column
+= offset
;
123 xloc2
.column
+= offset
;
125 /* Print the source line. */
126 pp_newline (context
->printer
);
127 const char *saved_prefix
= pp_get_prefix (context
->printer
);
128 pp_set_prefix (context
->printer
, NULL
);
129 pp_space (context
->printer
);
130 while (max_width
> 0 && line_width
> 0)
132 char c
= *line
== '\t' ? ' ' : *line
;
135 pp_character (context
->printer
, c
);
140 pp_newline (context
->printer
);
142 /* Print the caret under the line. */
143 const char *caret_cs
, *caret_ce
;
144 caret_cs
= colorize_start (pp_show_color (context
->printer
), "caret");
145 caret_ce
= colorize_stop (pp_show_color (context
->printer
));
146 int cmin
= xloc2
.column
147 ? MIN (xloc1
.column
, xloc2
.column
) : xloc1
.column
;
148 int caret_min
= cmin
== xloc1
.column
? caret1
: caret2
;
149 int caret_max
= cmin
== xloc1
.column
? caret2
: caret1
;
151 /* cmin is >= 1, but we indent with an extra space at the start like
154 for (i
= 0; i
< cmin
; i
++)
155 pp_space (context
->printer
);
156 pp_printf (context
->printer
, "%s%c%s", caret_cs
, caret_min
, caret_ce
);
160 for (i
++; i
< cmax
; i
++)
161 pp_space (context
->printer
);
162 pp_printf (context
->printer
, "%s%c%s", caret_cs
, caret_max
, caret_ce
);
164 pp_set_prefix (context
->printer
, saved_prefix
);
165 pp_needs_newline (context
->printer
) = true;