From 94812d17c8440ad4f6677961081963c19ef1d76e Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Thu, 23 Feb 2023 17:08:45 +0100 Subject: [PATCH 1/8] tweaks: rename a struct element, to avoid a theoretical name collision The header file form ncurses defines the name "tab". --- src/definitions.h | 2 +- src/nano.c | 2 +- src/rcfile.c | 4 ++-- src/text.c | 14 +++++++------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/definitions.h b/src/definitions.h index 288f1ff9..d6ca001d 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -432,7 +432,7 @@ typedef struct syntaxtype { /* The command with which to lint this type of file. */ char *formatter; /* The command with which to format/modify/arrange this type of file. */ - char *tab; + char *tabstring; /* What the Tab key should produce; NULL for default behavior. */ #ifdef ENABLE_COMMENT char *comment; diff --git a/src/nano.c b/src/nano.c index 4d5e7ea6..62430db9 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1107,7 +1107,7 @@ void toggle_this(int flag) refresh_needed = TRUE; break; case TABS_TO_SPACES: - if (openfile->syntax && openfile->syntax->tab) { + if (openfile->syntax && openfile->syntax->tabstring) { statusline(AHEM, _("Current syntax determines Tab")); TOGGLE(flag); return; diff --git a/src/rcfile.c b/src/rcfile.c index c225a565..9e09f5f4 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -674,7 +674,7 @@ void begin_new_syntax(char *ptr) live_syntax->magics = NULL; live_syntax->linter = NULL; live_syntax->formatter = NULL; - live_syntax->tab = NULL; + live_syntax->tabstring = NULL; #ifdef ENABLE_COMMENT live_syntax->comment = copy_of(GENERAL_COMMENT_CHARACTER); #endif @@ -1325,7 +1325,7 @@ bool parse_syntax_commands(char *keyword, char *ptr) pick_up_name("comment", ptr, &live_syntax->comment); #endif } else if (strcmp(keyword, "tabgives") == 0) { - pick_up_name("tabgives", ptr, &live_syntax->tab); + pick_up_name("tabgives", ptr, &live_syntax->tabstring); } else if (strcmp(keyword, "linter") == 0) pick_up_name("linter", ptr, &live_syntax->linter); else if (strcmp(keyword, "formatter") == 0) diff --git a/src/text.c b/src/text.c index f4a3d7c5..821aca0e 100644 --- a/src/text.c +++ b/src/text.c @@ -65,8 +65,8 @@ void do_mark(void) void do_tab(void) { #ifdef ENABLE_COLOR - if (openfile->syntax && openfile->syntax->tab) - inject(openfile->syntax->tab, strlen(openfile->syntax->tab)); + if (openfile->syntax && openfile->syntax->tabstring) + inject(openfile->syntax->tabstring, strlen(openfile->syntax->tabstring)); else #endif #ifndef NANO_TINY @@ -134,8 +134,8 @@ void do_indent(void) indentation = nmalloc(tabsize + 1); #ifdef ENABLE_COLOR - if (openfile->syntax && openfile->syntax->tab) - indentation = mallocstrcpy(indentation, openfile->syntax->tab); + if (openfile->syntax && openfile->syntax->tabstring) + indentation = mallocstrcpy(indentation, openfile->syntax->tabstring); else #endif /* Set the indentation to either a bunch of spaces or a single tab. */ @@ -173,10 +173,10 @@ size_t length_of_white(const char *text) size_t white_count = 0; #ifdef ENABLE_COLOR - if (openfile->syntax && openfile->syntax->tab) { - size_t thelength = strlen(openfile->syntax->tab); + if (openfile->syntax && openfile->syntax->tabstring) { + size_t thelength = strlen(openfile->syntax->tabstring); - while (text[white_count] == openfile->syntax->tab[white_count]) + while (text[white_count] == openfile->syntax->tabstring[white_count]) if (++white_count == thelength) return thelength; From b5157dd9cb3fefd9261c430d7bce9ac483b1124d Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Fri, 24 Feb 2023 17:15:42 +0100 Subject: [PATCH 2/8] tweaks: avoid calling isblank()/isalpha() on what could be a signed char The isxxxxx() functions expect their parameter to be either EOF or a value in the unsigned char range. Passing a negative char value could (in theory) result in unexpected behavior. --- src/nano.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nano.c b/src/nano.c index 62430db9..5d160e41 100644 --- a/src/nano.c +++ b/src/nano.c @@ -2205,7 +2205,7 @@ int main(int argc, char **argv) alt_speller = alt_speller_cmdline; } /* Strip leading whitespace from the speller command, if any. */ - while (alt_speller && *alt_speller && isblank(*alt_speller)) + while (alt_speller && (*alt_speller == ' ' || *alt_speller == '\t')) memmove(alt_speller, alt_speller + 1, strlen(alt_speller)); #endif @@ -2443,7 +2443,7 @@ int main(int argc, char **argv) #ifndef NANO_TINY int n = 1; - while (isalpha(argv[optind][n])) { + while (isalpha((unsigned char)argv[optind][n])) { switch (argv[optind][n++]) { case 'c': SET(CASE_SENSITIVE); break; case 'C': UNSET(CASE_SENSITIVE); break; From 5290a85afd67271af311e565d98fe279f73473a6 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 29 Jan 2023 23:43:00 +0100 Subject: [PATCH 3/8] new feature: interpret also : when opening a file Various tools will output filenames with line numbers in the format ::. Support this format in addition to the +, format when opening files. Signed-off-by: Benjamin Valentin Signed-off-by: Benno Schulenberg --- src/nano.c | 28 ++++++++++++++++++++++++++-- src/utils.c | 2 +- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/nano.c b/src/nano.c index 5d160e41..296f22dc 100644 --- a/src/nano.c +++ b/src/nano.c @@ -2482,8 +2482,32 @@ int main(int argc, char **argv) continue; } else #endif - if (!open_buffer(argv[optind++], TRUE)) - continue; + { + char *filename = argv[optind++]; + char *colon = filename + (*filename ? 1 : 0); + + /* Search for a colon, to open the file on a specific line. */ + while ((colon = strchr(colon, ':'))) { + + /* If the colon is escaped, unescape it and skip it. */ + if (*(colon - 1) == '\\') { + memmove(colon - 1, colon, strlen(colon) + 1); + continue; + } + + /* If parsing succeeds, cut off the line suffix. */ + if (parse_line_column(colon + 1, &givenline, &givencol)) { + *colon = 0; + break; + } + + /* Parsing failed; skip this colon. */ + ++colon; + } + + if (!open_buffer(filename, TRUE)) + continue; + } /* If a position was given on the command line, go there. */ if (givenline != 0 || givencol != 0) diff --git a/src/utils.c b/src/utils.c index 18c6e35c..3be197e2 100644 --- a/src/utils.c +++ b/src/utils.c @@ -137,7 +137,7 @@ bool parse_line_column(const char *str, ssize_t *line, ssize_t *column) while (*str == ' ') str++; - comma = strpbrk(str, "m,. /;"); + comma = strpbrk(str, "m,. /;:"); if (comma == NULL) return parse_num(str, line); From f1e238a9af2a30c67252d099e8f32698dead2ed9 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Thu, 9 Mar 2023 12:56:17 +0100 Subject: [PATCH 4/8] tweaks: condense the code that searches for a colon plus line number --- src/nano.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/nano.c b/src/nano.c index 296f22dc..bd069cd3 100644 --- a/src/nano.c +++ b/src/nano.c @@ -2486,23 +2486,17 @@ int main(int argc, char **argv) char *filename = argv[optind++]; char *colon = filename + (*filename ? 1 : 0); - /* Search for a colon, to open the file on a specific line. */ + /* Search the filename for a colon. If the colon is preceded by + * a backslash, elide the backslash and skip the colon. If there + * is a valid number after the colon, chop colon and number off. + * The number is later used to place the cursor on that line. */ while ((colon = strchr(colon, ':'))) { - - /* If the colon is escaped, unescape it and skip it. */ - if (*(colon - 1) == '\\') { + if (*(colon - 1) == '\\') memmove(colon - 1, colon, strlen(colon) + 1); - continue; - } - - /* If parsing succeeds, cut off the line suffix. */ - if (parse_line_column(colon + 1, &givenline, &givencol)) { - *colon = 0; - break; - } - - /* Parsing failed; skip this colon. */ - ++colon; + else if (parse_line_column(colon + 1, &givenline, &givencol)) + *colon = '\0'; + else + ++colon; } if (!open_buffer(filename, TRUE)) From bf984ecb9be286b81a3b2b2fb292f941357439d7 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Thu, 9 Mar 2023 16:14:44 +0100 Subject: [PATCH 5/8] docs: document the : thing for cursor positioning --- doc/nano.1 | 9 ++++++++- doc/nano.texi | 17 +++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/doc/nano.1 b/doc/nano.1 index 8fc40dff..fde6da75 100644 --- a/doc/nano.1 +++ b/doc/nano.1 @@ -25,6 +25,9 @@ nano \- Nano's ANOther editor, inspired by Pico .B nano .RI [ options "] [[\fB+" line [\fB, column "]] " file ]... .sp +.B nano +.RI [ options "] [" file [\fB: line [\fB: column "]]]..." +.sp .BR nano " [" \fIoptions "] [[" + [ crCR ]( / | ? ) \fIstring "] " \fIfile ]... .SH DESCRIPTION @@ -36,7 +39,11 @@ syntax coloring, line numbering, and soft-wrapping overlong lines. When giving a filename on the command line, the cursor can be put on a specific line by adding the line number with a plus sign (\fB+\fR) before the filename, and even in a specific column by adding it with a comma. -(Negative numbers count from the end of the file or line.) +Negative numbers count from the end of the file or line. +The line and column numbers may also be specified by gluing them with colons +after the filename. (When a filename contains a colon followed by digits, +escape the colon by preceding it with a triple backslash.) +.sp The cursor can be put on the first or last occurrence of a specific string by specifying that string after \fB+/\fR or \fB+?\fR before the filename. The string can be made case sensitive and/or caused to be interpreted as a diff --git a/doc/nano.texi b/doc/nano.texi index 8aca07b4..6ab23579 100644 --- a/doc/nano.texi +++ b/doc/nano.texi @@ -142,12 +142,17 @@ The usual way to invoke @command{nano} is: @blankline But it is also possible to specify one or more options (@pxref{Command-line Options}), -and to edit several files in a row. Additionally, the cursor -can be put on a specific line of a file by adding the line number -with a plus sign before the filename, and even in a specific column by -adding it with a comma. -(Negative numbers count from the end of the file or line.) -The cursor can also be put on the first or last occurrence of a specific string +and to edit several files in a row. + +The cursor can be put on a specific line of a file by adding +the line number with a plus sign before the filename, and even +in a specific column by adding it with a comma. +Negative numbers count from the end of the file or line. +The line and column numbers may also be specified by gluing them with colons +after the filename. (When a filename contains a colon followed by digits, +escape the colon by preceding it with a triple backslash.) + +The cursor can be put on the first or last occurrence of a specific string by specifying that string after @code{+/} or @code{+?} before the filename. The string can be made case sensitive and/or caused to be interpreted as a regular expression by inserting a @code{c} and/or @code{r} after the plus sign. From ffff6649185319c6d54aa8da25966e8bdac0c303 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Fri, 10 Mar 2023 15:07:24 +0100 Subject: [PATCH 6/8] tweaks: shrink the set of characters recognized as line-column separator This slightly reduces the chance that a filename is accidentally parsed as containing both a line and a column number at its end. --- src/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.c b/src/utils.c index 3be197e2..c5d467aa 100644 --- a/src/utils.c +++ b/src/utils.c @@ -137,7 +137,7 @@ bool parse_line_column(const char *str, ssize_t *line, ssize_t *column) while (*str == ' ') str++; - comma = strpbrk(str, "m,. /;:"); + comma = strpbrk(str, ",.:"); if (comma == NULL) return parse_num(str, line); From b8ead3b51144968401288291357452821193bb3b Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Mon, 27 Mar 2023 11:47:37 +0200 Subject: [PATCH 7/8] linter: use a format string, to deflect format-string attacks This fixes the first part of https://savannah.gnu.org/bugs/?63964. Reported-by: Vince Vince --- src/text.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/text.c b/src/text.c index 821aca0e..e3713c1d 100644 --- a/src/text.c +++ b/src/text.c @@ -2846,7 +2846,7 @@ void do_linter(void) confirm_margin(); #endif edit_refresh(); - statusline(NOTICE, curlint->msg); + statusline(NOTICE, "%s", curlint->msg); bottombars(MLINTER); } @@ -2877,7 +2877,7 @@ void do_linter(void) beep(); napms(600); last_wait = time(NULL); - statusline(NOTICE, curlint->msg); + statusline(NOTICE, "%s", curlint->msg); } } else if (function == do_page_down || function == to_next_block) { if (curlint->next != NULL) @@ -2887,7 +2887,7 @@ void do_linter(void) beep(); napms(600); last_wait = time(NULL); - statusline(NOTICE, curlint->msg); + statusline(NOTICE, "%s", curlint->msg); } } else beep(); From fdcafb83e3e23da645ca813991f448c907935673 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Mon, 27 Mar 2023 12:02:19 +0200 Subject: [PATCH 8/8] startup: use a format string, to deflect format-string attacks This fixes the second part of https://savannah.gnu.org/bugs/?63964. Reported-by: Vince Vince --- src/nano.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nano.c b/src/nano.c index bd069cd3..8578ee7d 100644 --- a/src/nano.c +++ b/src/nano.c @@ -2565,7 +2565,7 @@ int main(int argc, char **argv) #ifdef ENABLE_NANORC if (startup_problem != NULL) - statusline(ALERT, startup_problem); + statusline(ALERT, "%s", startup_problem); #define NOTREBOUND first_sc_for(MMAIN, do_help) && \ first_sc_for(MMAIN, do_help)->keycode == 0x07