mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-20 09:43:03 +00:00
diagnostics: truncate quoted sources to fit the screen
* src/location.c (min_int, columns): New. (location_caret): Compute the line width. Based on it, compute how many columns must be skipped before the quoted location and truncated after, to fit the sceen width. * tests/local.at (AT_QUELL_VALGRIND): Transform into... (AT_SET_ENV_IF, AT_SET_ENV): these. Define COLUMNS to protect the test suite from the user's environment.
This commit is contained in:
@@ -33,6 +33,26 @@
|
|||||||
|
|
||||||
location const empty_loc = EMPTY_LOCATION_INIT;
|
location const empty_loc = EMPTY_LOCATION_INIT;
|
||||||
|
|
||||||
|
static int
|
||||||
|
min_int (int a, int b)
|
||||||
|
{
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The terminal width. */
|
||||||
|
static int
|
||||||
|
columns (void)
|
||||||
|
{
|
||||||
|
const char *cp = getenv ("COLUMNS");
|
||||||
|
int res = 80;
|
||||||
|
if (cp && *cp)
|
||||||
|
{
|
||||||
|
unsigned long ul = strtoul (cp, NULL, 10);
|
||||||
|
res = ul < INT_MAX ? ul : INT_MAX;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/* If BUF is null, add BUFSIZE (which in this case must be less than
|
/* If BUF is null, add BUFSIZE (which in this case must be less than
|
||||||
INT_MAX) to COLUMN; otherwise, add mbsnwidth (BUF, BUFSIZE, 0) to
|
INT_MAX) to COLUMN; otherwise, add mbsnwidth (BUF, BUFSIZE, 0) to
|
||||||
COLUMN. If an overflow occurs, return INT_MAX. */
|
COLUMN. If an overflow occurs, return INT_MAX. */
|
||||||
@@ -179,6 +199,8 @@ static struct
|
|||||||
} caret_info;
|
} caret_info;
|
||||||
|
|
||||||
|
|
||||||
|
/* Open FILE for quoting, if needed, and if possible. Return whether
|
||||||
|
the file can quoted. */
|
||||||
static bool
|
static bool
|
||||||
caret_set_file (const char *file)
|
caret_set_file (const char *file)
|
||||||
{
|
{
|
||||||
@@ -276,6 +298,38 @@ location_caret (location loc, const char *style, FILE *out)
|
|||||||
FIXME: should be done in mbfile. */
|
FIXME: should be done in mbfile. */
|
||||||
caret_info.mbfile.eof_seen = 0;
|
caret_info.mbfile.eof_seen = 0;
|
||||||
|
|
||||||
|
/* Find the number of columns of this line. */
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
mbchar_t c;
|
||||||
|
caret_getc (c);
|
||||||
|
if (mb_iseof (c) || mb_iseq (c, '\n'))
|
||||||
|
break;
|
||||||
|
boundary_compute (&caret_info.pos, mb_ptr (c), mb_len (c));
|
||||||
|
}
|
||||||
|
int line_len = caret_info.pos.column;
|
||||||
|
|
||||||
|
/* Available width. Eight chars are consumed by the left-margin of
|
||||||
|
the quoting lines. */
|
||||||
|
int width = columns () - 8;
|
||||||
|
int skip = 0;
|
||||||
|
if (width < line_len)
|
||||||
|
{
|
||||||
|
/* We cannot quote the whole line. Make sure we can see the
|
||||||
|
beginning of the location. */
|
||||||
|
skip = width < loc.start.column ? loc.start.column - 10 : 0;
|
||||||
|
}
|
||||||
|
/* If we skip the initial part, we insert "..." before. */
|
||||||
|
if (skip)
|
||||||
|
width -= 3;
|
||||||
|
|
||||||
|
/* Go back to the beginning of line. */
|
||||||
|
fseek (caret_info.file, caret_info.offset, SEEK_SET);
|
||||||
|
/* Reset mbf's internal state.
|
||||||
|
FIXME: should be done in mbfile. */
|
||||||
|
caret_info.mbfile.eof_seen = 0;
|
||||||
|
caret_info.pos.column = 1;
|
||||||
|
|
||||||
/* Read the actual line. Don't update the offset, so that we keep a pointer
|
/* Read the actual line. Don't update the offset, so that we keep a pointer
|
||||||
to the start of the line. */
|
to the start of the line. */
|
||||||
{
|
{
|
||||||
@@ -283,15 +337,19 @@ location_caret (location loc, const char *style, FILE *out)
|
|||||||
caret_getc (c);
|
caret_getc (c);
|
||||||
if (!mb_iseof (c))
|
if (!mb_iseof (c))
|
||||||
{
|
{
|
||||||
bool single_line = loc.start.line == loc.end.line;
|
/* The last column to highlight. Only the first line of
|
||||||
|
multiline locations are quoted, in which case the ending
|
||||||
|
column is the end of line. Single point locations (with
|
||||||
|
equal boundaries) denote the character that they
|
||||||
|
follow. */
|
||||||
|
int col_end
|
||||||
|
= loc.start.line == loc.end.line
|
||||||
|
? loc.end.column + (loc.start.column == loc.end.column)
|
||||||
|
: line_len;
|
||||||
/* Quote the file (at most the first line in the case of
|
/* Quote the file (at most the first line in the case of
|
||||||
multiline locations). */
|
multiline locations). */
|
||||||
{
|
{
|
||||||
fprintf (out, "%5d | ", loc.start.line);
|
fprintf (out, "%5d | %s", loc.start.line, skip ? "..." : "");
|
||||||
/* Consider that single point location (with equal boundaries)
|
|
||||||
actually denote the character that they follow. */
|
|
||||||
int col_end = loc.end.column +
|
|
||||||
(single_line && loc.start.column == loc.end.column);
|
|
||||||
/* Whether we opened the style. If the line is not as
|
/* Whether we opened the style. If the line is not as
|
||||||
expected (maybe the file was changed since the scanner
|
expected (maybe the file was changed since the scanner
|
||||||
ran), we might reach the end before we actually saw the
|
ran), we might reach the end before we actually saw the
|
||||||
@@ -304,29 +362,35 @@ location_caret (location loc, const char *style, FILE *out)
|
|||||||
begin_use_class (style, out);
|
begin_use_class (style, out);
|
||||||
opened = true;
|
opened = true;
|
||||||
}
|
}
|
||||||
mb_putc (c, out);
|
if (skip < caret_info.pos.column)
|
||||||
|
mb_putc (c, out);
|
||||||
boundary_compute (&caret_info.pos, mb_ptr (c), mb_len (c));
|
boundary_compute (&caret_info.pos, mb_ptr (c), mb_len (c));
|
||||||
caret_getc (c);
|
caret_getc (c);
|
||||||
if (opened
|
if (opened
|
||||||
&& (single_line
|
&& (caret_info.pos.column == col_end
|
||||||
? caret_info.pos.column == col_end
|
|| width < caret_info.pos.column - skip))
|
||||||
: mb_iseq (c, '\n') || mb_iseof (c)))
|
{
|
||||||
end_use_class (style, out);
|
end_use_class (style, out);
|
||||||
|
opened = false;
|
||||||
|
}
|
||||||
|
if (width < caret_info.pos.column - skip)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
putc ('\n', out);
|
putc ('\n', out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the carets with the same indentation as above. */
|
/* Print the carets with the same indentation as above. */
|
||||||
{
|
{
|
||||||
fprintf (out, " | %*s", loc.start.column - 1, "");
|
fprintf (out, " | %s%*s",
|
||||||
|
skip ? "..." : "",
|
||||||
|
loc.start.column - 1 - skip, "");
|
||||||
begin_use_class (style, out);
|
begin_use_class (style, out);
|
||||||
putc ('^', out);
|
putc ('^', out);
|
||||||
/* Underlining a multiline location ends with the first
|
/* Underlining a multiline location ends with the first
|
||||||
line. */
|
line. */
|
||||||
int len = single_line
|
for (int i = loc.start.column - 1 - skip + 1,
|
||||||
? loc.end.column
|
i_end = min_int (col_end - 1 - skip, width);
|
||||||
: ftell (caret_info.file) - caret_info.offset;
|
i < i_end; ++i)
|
||||||
for (int i = loc.start.column + 1; i < len; ++i)
|
|
||||||
putc ('~', out);
|
putc ('~', out);
|
||||||
end_use_class (style, out);
|
end_use_class (style, out);
|
||||||
putc ('\n', out);
|
putc ('\n', out);
|
||||||
|
|||||||
@@ -118,7 +118,8 @@ unsigned location_print (location loc, FILE *out);
|
|||||||
left-over by the usage of location_caret. */
|
left-over by the usage of location_caret. */
|
||||||
void caret_free (void);
|
void caret_free (void);
|
||||||
|
|
||||||
/* Output to OUT the line and caret corresponding to location LOC. */
|
/* Quote the line containing LOC onto OUT. Highlight the part of LOC
|
||||||
|
with the color STYLE. */
|
||||||
void location_caret (location loc, const char* style, FILE *out);
|
void location_caret (location loc, const char* style, FILE *out);
|
||||||
|
|
||||||
/* Return -1, 0, 1, depending whether a is before, equal, or
|
/* Return -1, 0, 1, depending whether a is before, equal, or
|
||||||
|
|||||||
@@ -828,7 +828,7 @@ AT_BISON_CHECK_NO_XML($@)])
|
|||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
# Low-level macro to run bison once.
|
# Low-level macro to run bison once.
|
||||||
m4_define([AT_BISON_CHECK_],
|
m4_define([AT_BISON_CHECK_],
|
||||||
[AT_CHECK(AT_QUELL_VALGRIND[[ bison --color=no -fno-caret ]]$@)])
|
[AT_CHECK(AT_SET_ENV[[ bison --color=no -fno-caret ]]$@)])
|
||||||
|
|
||||||
|
|
||||||
# AT_BISON_CHECK_WARNINGS(BISON_ARGS, [OTHER_AT_CHECK_ARGS])
|
# AT_BISON_CHECK_WARNINGS(BISON_ARGS, [OTHER_AT_CHECK_ARGS])
|
||||||
@@ -884,7 +884,7 @@ fi]dnl
|
|||||||
# when a tortured grammar's XML is known to be too large for xsltproc to
|
# when a tortured grammar's XML is known to be too large for xsltproc to
|
||||||
# handle.
|
# handle.
|
||||||
m4_define([AT_BISON_CHECK_NO_XML],
|
m4_define([AT_BISON_CHECK_NO_XML],
|
||||||
[AT_CHECK(m4_null_if([$2], [], [AT_QUELL_VALGRIND ])[[bison --color=no -fno-caret ]]$@)
|
[AT_CHECK(AT_SET_ENV_IF([$2]) [[bison --color=no -fno-caret ]]$@)
|
||||||
AT_BISON_CHECK_WARNINGS($@)])
|
AT_BISON_CHECK_WARNINGS($@)])
|
||||||
|
|
||||||
# AT_BISON_CHECK_XML(BISON_ARGS, [OTHER_AT_CHECK_ARGS])
|
# AT_BISON_CHECK_XML(BISON_ARGS, [OTHER_AT_CHECK_ARGS])
|
||||||
@@ -911,20 +911,24 @@ m4_define([AT_BISON_CHECK_XML],
|
|||||||
m4_popdef([AT_BISON_ARGS])dnl
|
m4_popdef([AT_BISON_ARGS])dnl
|
||||||
[cp xml-tests/test.output expout]
|
[cp xml-tests/test.output expout]
|
||||||
AT_CHECK([[$XSLTPROC \
|
AT_CHECK([[$XSLTPROC \
|
||||||
`]]AT_QUELL_VALGRIND[[ bison --print-datadir`/xslt/xml2text.xsl \
|
`]]AT_SET_ENV[[ bison --print-datadir`/xslt/xml2text.xsl \
|
||||||
xml-tests/test.xml]], [[0]], [expout])
|
xml-tests/test.xml]], [[0]], [expout])
|
||||||
[sort xml-tests/test.gv > expout]
|
[sort xml-tests/test.gv > expout]
|
||||||
AT_CHECK([[$XSLTPROC \
|
AT_CHECK([[$XSLTPROC \
|
||||||
`]]AT_QUELL_VALGRIND[[ bison --print-datadir`/xslt/xml2dot.xsl \
|
`]]AT_SET_ENV[[ bison --print-datadir`/xslt/xml2dot.xsl \
|
||||||
xml-tests/test.xml | sort]], [[0]], [expout])
|
xml-tests/test.xml | sort]], [[0]], [expout])
|
||||||
[rm -rf xml-tests expout]
|
[rm -rf xml-tests expout]
|
||||||
AT_RESTORE_SPECIAL_FILES
|
AT_RESTORE_SPECIAL_FILES
|
||||||
[fi]])
|
[fi]])
|
||||||
|
|
||||||
# AT_QUELL_VALGRIND
|
|
||||||
# -----------------
|
# AT_SET_ENV_IF(EXIT-STATUS)
|
||||||
# Put this before a Bison invocation to keep Valgrind from complaining about
|
# --------------------------
|
||||||
# reachable memory.
|
# Put this before a Bison invocation to set the environment to:
|
||||||
|
# - define COLUMNS to make the test suite independant of the user's
|
||||||
|
# environment;
|
||||||
|
# - keep Valgrind from complaining about reachable memory (when
|
||||||
|
# EXIT-STATUS is not 0).
|
||||||
#
|
#
|
||||||
# Do not quote invocations of this macro within the first argument of AT_CHECK.
|
# Do not quote invocations of this macro within the first argument of AT_CHECK.
|
||||||
# The triple quoting below will cause test cases to fail if you do. If you do
|
# The triple quoting below will cause test cases to fail if you do. If you do
|
||||||
@@ -932,10 +936,15 @@ m4_define([AT_BISON_CHECK_XML],
|
|||||||
# will then fail to shell-escape its contents when attempting to print them.
|
# will then fail to shell-escape its contents when attempting to print them.
|
||||||
# The testsuite verbose output, at least, will be incorrect, but nothing may
|
# The testsuite verbose output, at least, will be incorrect, but nothing may
|
||||||
# fail to make sure you notice.
|
# fail to make sure you notice.
|
||||||
m4_define([AT_QUELL_VALGRIND],
|
m4_define([AT_SET_ENV_IF],
|
||||||
[[[VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=summary --show-reachable=no"; export VALGRIND_OPTS;]]])
|
[[[COLUMNS=1000; export COLUMNS;]] m4_null_if($1, [], [[[VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=summary --show-reachable=no"; export VALGRIND_OPTS; ]]])])
|
||||||
|
|
||||||
|
|
||||||
|
# AT_SET_ENV
|
||||||
|
# ----------
|
||||||
|
# See above.
|
||||||
|
m4_define([AT_SET_ENV],
|
||||||
|
[AT_SET_ENV_IF([1])])
|
||||||
|
|
||||||
## ------------------------ ##
|
## ------------------------ ##
|
||||||
## Compiling C, C++ Files. ##
|
## Compiling C, C++ Files. ##
|
||||||
|
|||||||
Reference in New Issue
Block a user