rcfile: fully read each included file, so all its syntaxes are seen

An included file can contain multiple syntaxes.  If reading would stop
as soon as a command different from 'syntax' and 'header' and 'magic'
is found, any later syntaxes would not be seen.  So each nanorc file
needs to be fully scanned -- it's just the interpretation of all the
color commands that we want to delay until the syntax gets actually
used.

This fixes https://savannah.gnu.org/bugs/?56478.

Bug existed since commit cba9d8d0 from a month ago.
This commit is contained in:
Benno Schulenberg 2019-06-13 12:20:38 +02:00
parent d7df7c694a
commit 7028adf211
2 changed files with 37 additions and 16 deletions

View File

@ -224,6 +224,8 @@ typedef struct syntaxtype {
/* The name of this syntax. */
char *filename;
/* File where the syntax is defined, or NULL if not an included file. */
size_t lineno;
/* The line number where the 'syntax' command was found. */
struct augmentstruct *augmentations;
/* List of extendsyntax commands to apply when loaded. */
regexlisttype *extensions;

View File

@ -330,7 +330,8 @@ void begin_a_syntax(char *ptr, bool headers_only)
/* Initialize a new syntax struct. */
live_syntax = (syntaxtype *)nmalloc(sizeof(syntaxtype));
live_syntax->name = mallocstrcpy(NULL, nameptr);
live_syntax->filename = (headers_only ? strdup(nanorc) : NULL);
live_syntax->filename = strdup(nanorc);
live_syntax->lineno = lineno;
live_syntax->augmentations = NULL;
live_syntax->extensions = NULL;
live_syntax->headers = NULL;
@ -989,6 +990,7 @@ bool parse_syntax_commands(char *keyword, char *ptr)
* to contain only color syntax commands. */
void parse_rcfile(FILE *rcstream, bool syntax_only, bool headers_only)
{
bool seen_color_command = FALSE;
char *buf = NULL;
ssize_t len;
size_t n = 0;
@ -1003,6 +1005,11 @@ void parse_rcfile(FILE *rcstream, bool syntax_only, bool headers_only)
buf[len - 1] = '\0';
lineno++;
/* If doing a full parse, skip to after the 'syntax' command. */
if (!headers_only && syntax_only && lineno <= live_syntax->lineno)
continue;
ptr = buf;
while (isblank((unsigned char)*ptr))
ptr++;
@ -1063,32 +1070,44 @@ void parse_rcfile(FILE *rcstream, bool syntax_only, bool headers_only)
/* Try to parse the keyword. */
if (strcasecmp(keyword, "syntax") == 0) {
if (headers_only || !syntax_only) {
if (opensyntax && lastcolor == NULL && live_syntax->filename == NULL)
if (headers_only) {
if (opensyntax && !seen_color_command)
rcfile_error(N_("Syntax \"%s\" has no color commands"),
live_syntax->name);
begin_a_syntax(ptr, headers_only);
}
seen_color_command = FALSE;
} else
break;
} else if (strcasecmp(keyword, "header") == 0) {
if (headers_only || !syntax_only)
if (headers_only)
grab_and_store("header", ptr, &live_syntax->headers);
} else if (strcasecmp(keyword, "magic") == 0) {
#ifdef HAVE_LIBMAGIC
if (headers_only || !syntax_only)
if (headers_only)
grab_and_store("magic", ptr, &live_syntax->magics);
#endif
} else if (headers_only)
break;
else if (parse_syntax_commands(keyword, ptr))
;
else if (syntax_only && (strcasecmp(keyword, "set") == 0 ||
} else if (syntax_only && (strcasecmp(keyword, "set") == 0 ||
strcasecmp(keyword, "unset") == 0 ||
strcasecmp(keyword, "bind") == 0 ||
strcasecmp(keyword, "unbind") == 0 ||
strcasecmp(keyword, "include") == 0 ||
strcasecmp(keyword, "extendsyntax") == 0))
rcfile_error(N_("Command \"%s\" not allowed in included file"),
strcasecmp(keyword, "extendsyntax") == 0)) {
if (headers_only)
rcfile_error(N_("Command \"%s\" not allowed in included file"),
keyword);
else
break;
} else if (headers_only && opensyntax &&
(strcasecmp(keyword, "color") == 0 ||
strcasecmp(keyword, "icolor") == 0)) {
seen_color_command = TRUE;
continue;
} else if (headers_only && opensyntax &&
(strcasecmp(keyword, "comment") == 0 ||
strcasecmp(keyword, "linter") == 0)) {
continue;
} else if (parse_syntax_commands(keyword, ptr))
;
else if (strcasecmp(keyword, "include") == 0)
parse_includes(ptr);
else
@ -1101,7 +1120,7 @@ void parse_rcfile(FILE *rcstream, bool syntax_only, bool headers_only)
parse_binding(ptr, TRUE);
else if (strcasecmp(keyword, "unbind") == 0)
parse_binding(ptr, FALSE);
else
else if (headers_only)
rcfile_error(N_("Command \"%s\" not understood"), keyword);
#ifdef ENABLE_COLOR
@ -1270,7 +1289,7 @@ void parse_rcfile(FILE *rcstream, bool syntax_only, bool headers_only)
}
#ifdef ENABLE_COLOR
if (opensyntax && lastcolor == NULL && !headers_only)
if (headers_only && !seen_color_command)
rcfile_error(N_("Syntax \"%s\" has no color commands"),
live_syntax->name);
@ -1298,7 +1317,7 @@ void parse_one_nanorc(void)
/* If opening the file succeeded, parse it. Otherwise, only
* complain if the file actually exists. */
if (rcstream != NULL)
parse_rcfile(rcstream, FALSE, FALSE);
parse_rcfile(rcstream, FALSE, TRUE);
else if (errno != ENOENT)
rcfile_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
}