files: look for digits and colons starting from the end of the filename

Starting from the end of the provided filename avoids needlessly looking
at colons that are somewhere in the middle of the path or the filename.

It also avoids inconsistenly interpreting a specified line number as a
column number when the filename itself ends with a colon plus digits
and the filename without the colon plus digits exists too.

This also removes the eliding of a backslash before a colon, which
would mangle the filename if the name actually contained a backslash
followed by a colon.

Negative line and column numbers are no longer allowed when using the
colon notation.

This fixes https://savannah.gnu.org/bugs/?65781,
and fixes https://savannah.gnu.org/bugs/?65782.

Problems existed since version 8.0, since colon parsing was introduced.
This commit is contained in:
Benno Schulenberg 2024-05-25 12:02:33 +02:00
parent 259a3c70e3
commit add945e717

View File

@ -2500,24 +2500,24 @@ int main(int argc, char **argv)
struct stat fileinfo;
/* If the filename contains a colon and this file does not exist,
* then check if the filename ends with a number (while skipping
* any colon preceded by a backslash and eliding the backslash).
* If there is a valid trailing number, chop colon and number off.
* then check if the filename ends with digits preceded by a colon
* (possibly preceded by more digits and a colon). If there is or
* are such trailing numbers, chop the colons plus numbers off.
* The number is later used to place the cursor on that line. */
if (strchr(filename, ':') && stat(filename, &fileinfo) < 0) {
char *colon = filename + (*filename ? 1 : 0);
while ((colon = strchr(colon, ':'))) {
if (*(colon - 1) == '\\')
memmove(colon - 1, colon, strlen(colon) + 1);
else if (parse_line_column(colon + 1, &givenline, &givencol)) {
*colon = '\0';
if (stat(filename, &fileinfo) < 0) {
*colon++ = ':';
givencol = 0;
}
} else
++colon;
char *coda = filename + strlen(filename);
maybe_two:
while (--coda > filename + 1 && ('0' <= *coda && *coda <= '9'))
;
if (*coda == ':' && ('0' <= *(coda + 1) && *(coda +1) <= '9')) {
*coda = '\0';
if (stat(filename, &fileinfo) < 0) {
*coda = ':';
/* If this was the first colon, look for a second one. */
if (!strchr(coda + 1, ':'))
goto maybe_two;
} else if (!parse_line_column(coda + 1, &givenline, &givencol))
die(_("Invalid number\n"));
}
}