commit 7028adf21165617d249d96af0381730c67447bb4
parent d7df7c694a2c785efa42c519a489db702338def3
Author: Benno Schulenberg <bensberg@telfort.nl>
Date: Thu, 13 Jun 2019 12:20:38 +0200
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.
Diffstat:
2 files changed, 37 insertions(+), 16 deletions(-)
diff --git a/src/nano.h b/src/nano.h
@@ -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;
diff --git a/src/rcfile.c b/src/rcfile.c
@@ -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));
}