From 9fec00429dd36ea51798afeaf5f6b9c1987b85cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20L=C3=B3pez-Ib=C3=A1=C3=B1ez?= Date: Wed, 11 Apr 2012 09:26:48 +0000 Subject: re PR c++/24985 (caret diagnostics) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2012-04-11 Manuel López-Ibáñez 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. From-SVN: r186305 --- gcc/diagnostic.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) (limited to 'gcc/diagnostic.c') diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index a68d6ce..60773d3 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); -- cgit v1.1