summaryrefslogtreecommitdiff
path: root/gcc/diagnostic.c
diff options
context:
space:
mode:
authormanu <manu@138bc75d-0d04-0410-961f-82ee72b054a4>2012-04-11 09:26:48 +0000
committermanu <manu@138bc75d-0d04-0410-961f-82ee72b054a4>2012-04-11 09:26:48 +0000
commit5a9830842f69ebb059061e26f8b0699cbd85121e (patch)
tree9e780906c85f6be0ad543abba26314c0c15e5512 /gcc/diagnostic.c
parent980af7e02e2f824385a01dea0b053074a70c1645 (diff)
downloadgcc-5a9830842f69ebb059061e26f8b0699cbd85121e.tar.gz
2012-04-11 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR 24985 gcc/ * diagnostic.h (show_caret): Declare. (caret_max_width): Declare. (diagnostic_show_locus): Declare. * diagnostic.c (diagnostic_initialize): Initialize to false. (diagnostic_show_locus): New. (diagnostic_report_diagnostic): Call it. (getenv_columns): New. (adjust_line): New. (diagnostic_set_caret_max_width): New. * input.c (read_line): New. (location_get_source_line): New. * input.h (location_get_source_line): Declare. * toplev.c (general_init): Initialize show_caret from options. * dwarf2out.c (gen_producer_string): Handle fdiagnostics-show-caret. * opts.c (common_handle_option): Likewise. * pretty-print.h (pp_get_prefix): New. (pp_base_get_prefix): New. * common.opt (fdiagnostics-show-caret): New option. * doc/invoke.texi (fdiagnostics-show-caret): Document it. testsuite/ * lib/prune.exp: Add -fno-diagnostics-show-caret. libstdc++-v3/ * testsuite/lib/prune.exp: Handle caret. libmudflap/ * testsuite/lib/libmudflap.exp: Handle caret. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@186305 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/diagnostic.c')
-rw-r--r--gcc/diagnostic.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index a68d6ce88ee..60773d3ac50 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -78,6 +78,35 @@ file_name_as_prefix (const char *f)
+/* Return the value of the getenv("COLUMNS") as an integer. If the
+ value is not set to a positive integer, then return INT_MAX. */
+static int
+getenv_columns (void)
+{
+ const char * s = getenv ("COLUMNS");
+ if (s != NULL) {
+ int n = atoi (s);
+ if (n > 0)
+ return n;
+ }
+ return INT_MAX;
+}
+
+/* Set caret_max_width to value. */
+void
+diagnostic_set_caret_max_width (diagnostic_context *context, int value)
+{
+ /* One minus to account for the leading empty space. */
+ value = value ? value - 1
+ : (isatty (fileno (context->printer->buffer->stream))
+ ? getenv_columns () - 1: INT_MAX);
+
+ if (value <= 0)
+ value = INT_MAX;
+
+ context->caret_max_width = value;
+}
+
/* Initialize the diagnostic message outputting machinery. */
void
diagnostic_initialize (diagnostic_context *context, int n_opts)
@@ -100,6 +129,8 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
context->classify_diagnostic = XNEWVEC (diagnostic_t, n_opts);
for (i = 0; i < n_opts; i++)
context->classify_diagnostic[i] = DK_UNSPECIFIED;
+ context->show_caret = false;
+ diagnostic_set_caret_max_width (context, pp_line_cutoff (context->printer));
context->show_option_requested = false;
context->abort_on_error = false;
context->show_column = false;
@@ -196,6 +227,72 @@ diagnostic_build_prefix (diagnostic_context *context,
: build_message_string ("%s:%d: %s", s.file, s.line, text));
}
+/* If LINE is longer than MAX_WIDTH, and COLUMN is not smaller than
+ MAX_WIDTH by some margin, then adjust the start of the line such
+ that the COLUMN is smaller than MAX_WIDTH minus the margin. The
+ margin is either 10 characters or the difference between the column
+ and the length of the line, whatever is smaller. */
+static const char *
+adjust_line (const char *line, int max_width, int *column_p)
+{
+ int right_margin = 10;
+ int line_width = strlen (line);
+ int column = *column_p;
+
+ right_margin = MIN(line_width - column, right_margin);
+ right_margin = max_width - right_margin;
+ if (line_width >= max_width && column > right_margin)
+ {
+ line += column - right_margin;
+ *column_p = right_margin;
+ }
+ return line;
+}
+
+/* Print the physical source line corresponding to the location of
+ this diagnostics, and a caret indicating the precise column. */
+void
+diagnostic_show_locus (diagnostic_context * context,
+ const diagnostic_info *diagnostic)
+{
+ const char *line;
+ char *buffer;
+ expanded_location s;
+ int max_width;
+ const char *saved_prefix;
+
+
+ if (!context->show_caret
+ || diagnostic->location <= BUILTINS_LOCATION)
+ return;
+
+ s = expand_location(diagnostic->location);
+ line = location_get_source_line (s);
+ if (line == NULL)
+ return;
+
+ max_width = context->caret_max_width;
+ line = adjust_line (line, max_width, &(s.column));
+
+ pp_newline (context->printer);
+ saved_prefix = pp_get_prefix (context->printer);
+ pp_set_prefix (context->printer, NULL);
+ pp_character (context->printer, ' ');
+ while (max_width > 0 && *line != '\0')
+ {
+ char c = *line == '\t' ? ' ' : *line;
+ pp_character (context->printer, c);
+ max_width--;
+ line++;
+ }
+ pp_newline (context->printer);
+ /* pp_printf does not implement %*c. */
+ buffer = XALLOCAVEC (char, s.column + 3);
+ snprintf (buffer, s.column + 3, " %*c", s.column, '^');
+ pp_string (context->printer, buffer);
+ pp_set_prefix (context->printer, saved_prefix);
+}
+
/* Take any action which is expected to happen after the diagnostic
is written out. This function does not always return. */
static void
@@ -547,6 +644,7 @@ diagnostic_report_diagnostic (diagnostic_context *context,
pp_format (context->printer, &diagnostic->message);
(*diagnostic_starter (context)) (context, diagnostic);
pp_output_formatted_text (context->printer);
+ diagnostic_show_locus (context, diagnostic);
(*diagnostic_finalizer (context)) (context, diagnostic);
pp_flush (context->printer);
diagnostic_action_after_output (context, diagnostic);