2001-04-18 04:28:54 +00:00
|
|
|
/**************************************************************************
|
2016-08-29 15:10:49 +00:00
|
|
|
* rcfile.c -- This file is part of GNU nano. *
|
2001-04-18 04:28:54 +00:00
|
|
|
* *
|
2021-01-11 13:21:03 +00:00
|
|
|
* Copyright (C) 2001-2011, 2013-2021 Free Software Foundation, Inc. *
|
2016-08-29 13:14:18 +00:00
|
|
|
* Copyright (C) 2014 Mike Frysinger *
|
2019-05-20 08:45:33 +00:00
|
|
|
* Copyright (C) 2019 Brand Huntsman *
|
2020-03-11 10:52:15 +00:00
|
|
|
* Copyright (C) 2014-2020 Benno Schulenberg *
|
2016-08-29 13:14:18 +00:00
|
|
|
* *
|
2016-08-29 15:10:49 +00:00
|
|
|
* GNU nano is free software: you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published *
|
|
|
|
* by the Free Software Foundation, either version 3 of the License, *
|
|
|
|
* or (at your option) any later version. *
|
2001-04-18 04:28:54 +00:00
|
|
|
* *
|
2016-08-29 15:10:49 +00:00
|
|
|
* GNU nano is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty *
|
|
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
|
|
* See the GNU General Public License for more details. *
|
2001-04-18 04:28:54 +00:00
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
2016-08-29 15:10:49 +00:00
|
|
|
* along with this program. If not, see http://www.gnu.org/licenses/. *
|
2001-04-18 04:28:54 +00:00
|
|
|
* *
|
|
|
|
**************************************************************************/
|
|
|
|
|
2020-06-20 10:09:31 +00:00
|
|
|
#include "prototypes.h"
|
2002-09-13 18:14:04 +00:00
|
|
|
|
2019-10-13 16:51:15 +00:00
|
|
|
#ifdef ENABLE_NANORC
|
|
|
|
|
2017-08-06 11:32:44 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
2014-03-30 20:37:40 +00:00
|
|
|
#include <glob.h>
|
2001-04-18 04:28:54 +00:00
|
|
|
#include <string.h>
|
2002-05-11 03:04:44 +00:00
|
|
|
#include <unistd.h>
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2016-11-27 15:34:34 +00:00
|
|
|
#ifndef RCFILE_NAME
|
2020-05-29 16:45:14 +00:00
|
|
|
#define HOME_RC_NAME ".nanorc"
|
|
|
|
#define RCFILE_NAME "nanorc"
|
2018-04-20 08:47:10 +00:00
|
|
|
#else
|
2020-05-29 16:45:14 +00:00
|
|
|
#define HOME_RC_NAME RCFILE_NAME
|
2016-11-27 15:34:34 +00:00
|
|
|
#endif
|
|
|
|
|
2006-08-21 21:37:39 +00:00
|
|
|
static const rcoption rcopts[] = {
|
2017-12-29 18:27:33 +00:00
|
|
|
{"boldtext", BOLD_TEXT},
|
2017-10-31 16:34:07 +00:00
|
|
|
#ifdef ENABLE_JUSTIFY
|
2017-12-29 18:27:33 +00:00
|
|
|
{"brackets", 0},
|
2019-01-28 18:45:12 +00:00
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_WRAPPING
|
|
|
|
{"breaklonglines", BREAK_LONG_LINES},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
2020-05-25 16:59:12 +00:00
|
|
|
{"casesensitive", CASE_SENSITIVE},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"constantshow", CONSTANT_SHOW},
|
2017-10-31 16:39:30 +00:00
|
|
|
#ifdef ENABLED_WRAPORJUSTIFY
|
2017-12-29 18:27:33 +00:00
|
|
|
{"fill", 0},
|
2002-07-19 01:08:59 +00:00
|
|
|
#endif
|
2017-10-29 18:42:12 +00:00
|
|
|
#ifdef ENABLE_HISTORIES
|
2017-12-29 18:27:33 +00:00
|
|
|
{"historylog", HISTORYLOG},
|
2018-05-13 07:47:40 +00:00
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_LINENUMBERS
|
|
|
|
{"linenumbers", LINE_NUMBERS},
|
2020-09-21 07:23:37 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_LIBMAGIC
|
|
|
|
{"magic", USE_MAGIC},
|
2013-01-01 03:24:39 +00:00
|
|
|
#endif
|
2017-05-01 18:45:07 +00:00
|
|
|
#ifdef ENABLE_MOUSE
|
2017-12-29 18:27:33 +00:00
|
|
|
{"mouse", USE_MOUSE},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
2017-05-01 18:20:34 +00:00
|
|
|
#ifdef ENABLE_MULTIBUFFER
|
2017-12-29 18:27:33 +00:00
|
|
|
{"multibuffer", MULTIBUFFER},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
{"nohelp", NO_HELP},
|
2019-04-07 07:01:52 +00:00
|
|
|
{"nonewlines", NO_NEWLINES},
|
2017-10-29 20:00:09 +00:00
|
|
|
#ifdef ENABLE_WRAPPING
|
2021-01-02 15:55:17 +00:00
|
|
|
{"nowrap", NO_WRAP}, /* Deprecated; remove in 2024. */
|
2002-07-19 01:08:59 +00:00
|
|
|
#endif
|
2017-10-29 20:08:07 +00:00
|
|
|
#ifdef ENABLE_OPERATINGDIR
|
2017-12-29 18:27:33 +00:00
|
|
|
{"operatingdir", 0},
|
2015-06-18 18:51:27 +00:00
|
|
|
#endif
|
2017-10-29 18:42:12 +00:00
|
|
|
#ifdef ENABLE_HISTORIES
|
2018-09-30 11:27:08 +00:00
|
|
|
{"positionlog", POSITIONLOG},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
{"preserve", PRESERVE},
|
2017-10-31 16:34:07 +00:00
|
|
|
#ifdef ENABLE_JUSTIFY
|
2017-12-29 18:27:33 +00:00
|
|
|
{"punct", 0},
|
|
|
|
{"quotestr", 0},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
{"quickblank", QUICK_BLANK},
|
2018-12-31 17:34:28 +00:00
|
|
|
{"rawsequences", RAW_SEQUENCES},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"rebinddelete", REBIND_DELETE},
|
|
|
|
{"regexp", USE_REGEXP},
|
2020-04-30 15:25:48 +00:00
|
|
|
{"saveonexit", SAVE_ON_EXIT},
|
2017-10-31 18:32:42 +00:00
|
|
|
#ifdef ENABLE_SPELLER
|
2017-12-29 18:27:33 +00:00
|
|
|
{"speller", 0},
|
2002-06-28 22:45:14 +00:00
|
|
|
#endif
|
2020-03-13 15:17:10 +00:00
|
|
|
{"suspend", SUSPENDABLE}, /* Deprecated; remove in 2022. */
|
2021-10-24 08:20:05 +00:00
|
|
|
{"suspendable", SUSPENDABLE}, /* Obsolete; remove in 2022. */
|
2020-04-30 15:25:48 +00:00
|
|
|
{"tempfile", SAVE_ON_EXIT}, /* Deprecated; remove in 2022. */
|
2005-11-15 03:17:35 +00:00
|
|
|
#ifndef NANO_TINY
|
2018-04-30 20:10:27 +00:00
|
|
|
{"afterends", AFTER_ENDS},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"allow_insecure_backup", INSECURE_BACKUP},
|
|
|
|
{"atblanks", AT_BLANKS},
|
|
|
|
{"autoindent", AUTOINDENT},
|
2020-05-25 16:52:09 +00:00
|
|
|
{"backup", MAKE_BACKUP},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"backupdir", 0},
|
2019-12-18 16:19:04 +00:00
|
|
|
{"bookstyle", BOOKSTYLE},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"cutfromcursor", CUT_FROM_CURSOR},
|
2020-09-21 15:04:10 +00:00
|
|
|
{"emptyline", EMPTY_LINE},
|
2018-12-17 18:57:30 +00:00
|
|
|
{"guidestripe", 0},
|
2020-05-26 17:07:42 +00:00
|
|
|
{"indicator", INDICATOR},
|
2020-09-21 15:04:10 +00:00
|
|
|
{"jumpyscrolling", JUMPY_SCROLLING},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"locking", LOCKING},
|
|
|
|
{"matchbrackets", 0},
|
2020-08-16 06:17:03 +00:00
|
|
|
{"minibar", MINIBAR},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"noconvert", NO_CONVERT},
|
|
|
|
{"showcursor", SHOW_CURSOR},
|
|
|
|
{"smarthome", SMART_HOME},
|
|
|
|
{"softwrap", SOFTWRAP},
|
2020-09-19 17:50:45 +00:00
|
|
|
{"stateflags", STATEFLAGS},
|
2020-10-03 09:21:18 +00:00
|
|
|
{"tabsize", 0},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"tabstospaces", TABS_TO_SPACES},
|
|
|
|
{"trimblanks", TRIM_BLANKS},
|
|
|
|
{"unix", MAKE_IT_UNIX},
|
|
|
|
{"whitespace", 0},
|
|
|
|
{"wordbounds", WORD_BOUNDS},
|
|
|
|
{"wordchars", 0},
|
2018-10-24 09:02:08 +00:00
|
|
|
{"zap", LET_THEM_ZAP},
|
2021-10-28 10:51:29 +00:00
|
|
|
{"zero", ZERO},
|
2014-05-03 18:24:45 +00:00
|
|
|
#endif
|
2017-11-01 18:45:33 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2017-12-29 18:27:33 +00:00
|
|
|
{"titlecolor", 0},
|
|
|
|
{"numbercolor", 0},
|
2019-03-03 10:04:19 +00:00
|
|
|
{"stripecolor", 0},
|
2020-08-28 16:40:10 +00:00
|
|
|
{"scrollercolor", 0},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"selectedcolor", 0},
|
2021-03-03 08:31:46 +00:00
|
|
|
{"spotlightcolor", 0},
|
2021-06-07 10:10:23 +00:00
|
|
|
{"minicolor", 0},
|
2020-12-06 14:49:35 +00:00
|
|
|
{"promptcolor", 0},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"statuscolor", 0},
|
2018-02-20 08:50:54 +00:00
|
|
|
{"errorcolor", 0},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"keycolor", 0},
|
|
|
|
{"functioncolor", 0},
|
2004-05-29 16:25:30 +00:00
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
{NULL, 0}
|
2002-01-19 16:52:34 +00:00
|
|
|
};
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2005-06-28 06:25:34 +00:00
|
|
|
static size_t lineno = 0;
|
2017-12-29 18:27:33 +00:00
|
|
|
/* The line number of the last encountered error. */
|
2005-03-10 20:55:11 +00:00
|
|
|
static char *nanorc = NULL;
|
2017-12-29 18:27:33 +00:00
|
|
|
/* The path to the rcfile we're parsing. */
|
2017-11-01 18:45:33 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2016-02-28 20:38:14 +00:00
|
|
|
static bool opensyntax = FALSE;
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Whether we're allowed to add to the last syntax. When a file ends,
|
|
|
|
* or when a new syntax command is seen, this bool becomes FALSE. */
|
2016-03-10 20:36:12 +00:00
|
|
|
static syntaxtype *live_syntax;
|
2017-12-29 18:27:33 +00:00
|
|
|
/* The syntax that is currently being parsed. */
|
2019-06-15 17:34:23 +00:00
|
|
|
static bool seen_color_command = FALSE;
|
|
|
|
/* Whether a syntax definition contains any color commands. */
|
2016-03-13 20:05:36 +00:00
|
|
|
static colortype *lastcolor = NULL;
|
2017-12-29 18:27:33 +00:00
|
|
|
/* The end of the color list for the current syntax. */
|
2005-03-10 20:55:11 +00:00
|
|
|
#endif
|
2019-12-13 17:54:53 +00:00
|
|
|
|
2020-05-31 09:57:47 +00:00
|
|
|
#define NUMBER_OF_MENUS 17 /* Remove the deprecated 'extcmd' in 2022. */
|
2019-12-13 17:54:53 +00:00
|
|
|
char *menunames[NUMBER_OF_MENUS] = { "main", "search", "replace", "replacewith",
|
|
|
|
"yesno", "gotoline", "writeout", "insert",
|
2020-05-31 09:57:47 +00:00
|
|
|
"execute", "extcmd", "help", "spell", "linter",
|
2019-12-13 17:54:53 +00:00
|
|
|
"browser", "whereisfile", "gotodir",
|
|
|
|
"all" };
|
|
|
|
int menusymbols[NUMBER_OF_MENUS] = { MMAIN, MWHEREIS, MREPLACE, MREPLACEWITH,
|
|
|
|
MYESNO, MGOTOLINE, MWRITEFILE, MINSERTFILE,
|
2020-05-31 09:57:47 +00:00
|
|
|
MEXECUTE, MEXECUTE, MHELP, MSPELL, MLINTER,
|
2019-12-13 17:54:53 +00:00
|
|
|
MBROWSER, MWHEREISFILE, MGOTODIR,
|
|
|
|
MMOST|MBROWSER|MHELP|MYESNO };
|
2019-11-25 18:17:41 +00:00
|
|
|
#endif /* ENABLE_NANORC */
|
2002-01-18 21:54:35 +00:00
|
|
|
|
2019-11-25 18:17:41 +00:00
|
|
|
#if defined(ENABLE_NANORC) || defined(ENABLE_HISTORIES)
|
2019-05-13 23:43:53 +00:00
|
|
|
static linestruct *errors_head = NULL;
|
|
|
|
static linestruct *errors_tail = NULL;
|
|
|
|
/* Beginning and end of a list of errors in rcfiles, if any. */
|
|
|
|
|
|
|
|
/* Send the gathered error messages (if any) to the terminal. */
|
2019-09-30 17:01:04 +00:00
|
|
|
void display_rcfile_errors(void)
|
2019-05-13 23:43:53 +00:00
|
|
|
{
|
|
|
|
for (linestruct *error = errors_head; error != NULL; error = error->next)
|
|
|
|
fprintf(stderr, "%s\n", error->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAXSIZE (PATH_MAX + 200)
|
|
|
|
|
2019-06-15 12:07:57 +00:00
|
|
|
/* Store the given error message in a linked list, to be printed upon exit. */
|
|
|
|
void jot_error(const char *msg, ...)
|
2001-04-18 04:28:54 +00:00
|
|
|
{
|
2019-05-13 23:43:53 +00:00
|
|
|
linestruct *error = make_new_node(errors_tail);
|
|
|
|
char textbuf[MAXSIZE];
|
|
|
|
int length = 0;
|
2017-12-29 18:27:33 +00:00
|
|
|
va_list ap;
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2019-05-13 23:43:53 +00:00
|
|
|
if (errors_head == NULL)
|
|
|
|
errors_head = error;
|
|
|
|
else
|
|
|
|
errors_tail->next = error;
|
|
|
|
errors_tail = error;
|
|
|
|
|
2019-10-20 12:25:22 +00:00
|
|
|
if (startup_problem == NULL) {
|
2019-11-25 18:17:41 +00:00
|
|
|
#ifdef ENABLE_NANORC
|
2019-10-20 12:25:22 +00:00
|
|
|
if (nanorc != NULL) {
|
|
|
|
snprintf(textbuf, MAXSIZE, _("Mistakes in '%s'"), nanorc);
|
|
|
|
startup_problem = copy_of(textbuf);
|
|
|
|
} else
|
2019-11-25 18:17:41 +00:00
|
|
|
#endif
|
2019-10-20 12:25:22 +00:00
|
|
|
startup_problem = copy_of(_("Problems with history file"));
|
|
|
|
}
|
2019-11-25 18:17:41 +00:00
|
|
|
#ifdef ENABLE_NANORC
|
2017-12-29 18:27:33 +00:00
|
|
|
if (lineno > 0)
|
2019-05-13 23:43:53 +00:00
|
|
|
length = snprintf(textbuf, MAXSIZE, _("Error in %s on line %zu: "),
|
|
|
|
nanorc, lineno);
|
2019-11-25 18:17:41 +00:00
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
va_start(ap, msg);
|
2019-05-13 23:43:53 +00:00
|
|
|
length += vsnprintf(textbuf + length, MAXSIZE - length, _(msg), ap);
|
2017-12-29 18:27:33 +00:00
|
|
|
va_end(ap);
|
2004-08-11 05:13:08 +00:00
|
|
|
|
2019-05-13 23:43:53 +00:00
|
|
|
error->data = nmalloc(length + 1);
|
|
|
|
sprintf(error->data, "%s", textbuf);
|
2001-04-18 04:28:54 +00:00
|
|
|
}
|
2019-11-25 18:17:41 +00:00
|
|
|
#endif /* ENABLE_NANORC || ENABLE_HISTORIES */
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2019-11-25 18:17:41 +00:00
|
|
|
#ifdef ENABLE_NANORC
|
2019-12-13 17:54:53 +00:00
|
|
|
/* Interpret a function string given in the rc file, and return a
|
|
|
|
* shortcut record with the corresponding function filled in. */
|
|
|
|
keystruct *strtosc(const char *input)
|
|
|
|
{
|
|
|
|
keystruct *s = nmalloc(sizeof(keystruct));
|
|
|
|
|
|
|
|
#ifndef NANO_TINY
|
|
|
|
s->toggle = 0;
|
|
|
|
#endif
|
|
|
|
|
2019-12-13 18:06:39 +00:00
|
|
|
if (!strcmp(input, "cancel"))
|
|
|
|
s->func = do_cancel;
|
2019-12-13 17:54:53 +00:00
|
|
|
#ifdef ENABLE_HELP
|
2019-12-13 18:06:39 +00:00
|
|
|
else if (!strcmp(input, "help"))
|
2019-12-15 18:47:05 +00:00
|
|
|
s->func = do_help;
|
2019-12-13 17:54:53 +00:00
|
|
|
#endif
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "exit"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_exit;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "discardbuffer"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = discard_buffer;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "writeout"))
|
2021-11-08 15:41:44 +00:00
|
|
|
s->func = do_writeout;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "savefile"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_savefile;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "insert"))
|
2021-11-08 15:54:18 +00:00
|
|
|
s->func = do_insertfile;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "whereis"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_search_forward;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "wherewas"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_search_backward;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "findprevious"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_findprevious;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "findnext"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_findnext;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "replace"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_replace;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "cut"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = cut_text;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "paste"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = paste_text;
|
|
|
|
#ifndef NANO_TINY
|
2020-06-15 12:27:49 +00:00
|
|
|
else if (!strcmp(input, "execute"))
|
|
|
|
s->func = do_execute;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "cutrestoffile"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = cut_till_eof;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "copy"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = copy_text;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "zap"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = zap_text;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "mark"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_mark;
|
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_SPELLER
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "tospell") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "speller"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_spell;
|
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_COLOR
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "linter"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_linter;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "formatter"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_formatter;
|
|
|
|
#endif
|
2020-07-05 09:02:41 +00:00
|
|
|
else if (!strcmp(input, "location") ||
|
|
|
|
!strcmp(input, "curpos")) /* Deprecated; remove in 2022. */
|
2020-07-03 10:39:04 +00:00
|
|
|
s->func = report_cursor_position;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "gotoline"))
|
2021-11-09 09:18:03 +00:00
|
|
|
s->func = do_gotolinecolumn;
|
2019-12-13 17:54:53 +00:00
|
|
|
#ifdef ENABLE_JUSTIFY
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "justify"))
|
2021-06-13 10:14:35 +00:00
|
|
|
s->func = do_justify;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "fulljustify"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_full_justify;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "beginpara"))
|
2020-03-11 18:47:21 +00:00
|
|
|
s->func = to_para_begin;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "endpara"))
|
2020-03-11 18:47:21 +00:00
|
|
|
s->func = to_para_end;
|
2019-12-13 17:54:53 +00:00
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_COMMENT
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "comment"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_comment;
|
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_WORDCOMPLETION
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "complete"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = complete_a_word;
|
|
|
|
#endif
|
|
|
|
#ifndef NANO_TINY
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "indent"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_indent;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "unindent"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_unindent;
|
2021-10-07 10:24:38 +00:00
|
|
|
else if (!strcmp(input, "chopwordleft"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = chop_previous_word;
|
2021-10-07 10:24:38 +00:00
|
|
|
else if (!strcmp(input, "chopwordright"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = chop_next_word;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "findbracket"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_find_bracket;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "wordcount"))
|
2021-10-22 09:47:15 +00:00
|
|
|
s->func = count_lines_words_and_characters;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "recordmacro"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = record_macro;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "runmacro"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = run_macro;
|
2020-04-06 15:42:29 +00:00
|
|
|
else if (!strcmp(input, "anchor"))
|
|
|
|
s->func = put_or_lift_anchor;
|
|
|
|
else if (!strcmp(input, "prevanchor"))
|
|
|
|
s->func = to_prev_anchor;
|
|
|
|
else if (!strcmp(input, "nextanchor"))
|
|
|
|
s->func = to_next_anchor;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "undo"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_undo;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "redo"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_redo;
|
|
|
|
#endif
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "left") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "back"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_left;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "right") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "forward"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_right;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "up") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "prevline"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_up;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "down") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "nextline"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_down;
|
|
|
|
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "scrollup"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_scroll_up;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "scrolldown"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_scroll_down;
|
2016-04-27 13:10:06 +00:00
|
|
|
else if (!strcmp(input, "center"))
|
|
|
|
s->func = do_center;
|
2019-12-13 17:54:53 +00:00
|
|
|
#endif
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "prevword"))
|
2020-03-11 18:43:03 +00:00
|
|
|
s->func = to_prev_word;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "nextword"))
|
2020-03-11 18:43:03 +00:00
|
|
|
s->func = to_next_word;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "home"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_home;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "end"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_end;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "prevblock"))
|
2020-03-11 18:45:06 +00:00
|
|
|
s->func = to_prev_block;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "nextblock"))
|
2020-03-11 18:45:06 +00:00
|
|
|
s->func = to_next_block;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "pageup") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "prevpage"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_page_up;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "pagedown") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "nextpage"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_page_down;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "firstline"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = to_first_line;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "lastline"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = to_last_line;
|
|
|
|
#ifdef ENABLE_MULTIBUFFER
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "prevbuf"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = switch_to_prev_buffer;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "nextbuf"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = switch_to_next_buffer;
|
|
|
|
#endif
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "verbatim"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_verbatim_input;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "tab"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_tab;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "enter"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_enter;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "delete"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_delete;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "backspace"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_backspace;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "refresh"))
|
2020-05-31 14:41:07 +00:00
|
|
|
s->func = full_refresh;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "suspend"))
|
2021-11-09 09:39:31 +00:00
|
|
|
s->func = do_suspend;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "casesens"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = case_sens_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "regexp"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = regexp_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "backwards"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = backwards_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "flipreplace"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = flip_replace;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "flipgoto"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = flip_goto;
|
|
|
|
#ifdef ENABLE_HISTORIES
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "older"))
|
2021-10-09 15:30:33 +00:00
|
|
|
s->func = get_older_item;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "newer"))
|
2021-10-09 15:30:33 +00:00
|
|
|
s->func = get_newer_item;
|
2019-12-13 17:54:53 +00:00
|
|
|
#endif
|
|
|
|
#ifndef NANO_TINY
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "dosformat"))
|
2021-10-08 08:53:04 +00:00
|
|
|
s->func = dos_format;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "macformat"))
|
2021-10-08 08:53:04 +00:00
|
|
|
s->func = mac_format;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "append"))
|
2021-10-08 08:53:04 +00:00
|
|
|
s->func = append_it;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "prepend"))
|
2021-10-08 08:53:04 +00:00
|
|
|
s->func = prepend_it;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "backup"))
|
2021-10-08 08:53:04 +00:00
|
|
|
s->func = back_it_up;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "flipexecute"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = flip_execute;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "flippipe"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = flip_pipe;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "flipconvert"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = flip_convert;
|
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_MULTIBUFFER
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "flipnewbuffer"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = flip_newbuffer;
|
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_BROWSER
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "tofiles") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "browser"))
|
2020-01-26 15:36:23 +00:00
|
|
|
s->func = to_files;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "gotodir"))
|
2020-01-26 15:36:23 +00:00
|
|
|
s->func = goto_dir;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "firstfile"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = to_first_file;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "lastfile"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = to_last_file;
|
|
|
|
#endif
|
|
|
|
else {
|
|
|
|
#ifndef NANO_TINY
|
2021-11-08 15:16:35 +00:00
|
|
|
s->func = do_toggle;
|
2019-12-13 18:03:38 +00:00
|
|
|
if (!strcmp(input, "nohelp"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = NO_HELP;
|
2021-10-28 10:51:29 +00:00
|
|
|
else if (!strcmp(input, "zero"))
|
|
|
|
s->toggle = ZERO;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "constantshow"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = CONSTANT_SHOW;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "softwrap"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = SOFTWRAP;
|
|
|
|
#ifdef ENABLE_LINENUMBERS
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "linenumbers"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = LINE_NUMBERS;
|
|
|
|
#endif
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "whitespacedisplay"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = WHITESPACE_DISPLAY;
|
|
|
|
#ifdef ENABLE_COLOR
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "nosyntax"))
|
2020-05-01 11:25:15 +00:00
|
|
|
s->toggle = NO_SYNTAX;
|
2019-12-13 17:54:53 +00:00
|
|
|
#endif
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "smarthome"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = SMART_HOME;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "autoindent"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = AUTOINDENT;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "cutfromcursor"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = CUT_FROM_CURSOR;
|
|
|
|
#ifdef ENABLE_WRAPPING
|
2021-01-02 16:06:36 +00:00
|
|
|
else if (!strcmp(input, "breaklonglines") ||
|
|
|
|
!strcmp(input, "nowrap")) /* Deprecated; remove in 2024. */
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = BREAK_LONG_LINES;
|
|
|
|
#endif
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "tabstospaces"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = TABS_TO_SPACES;
|
|
|
|
#ifdef ENABLE_MOUSE
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "mouse"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = USE_MOUSE;
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
#endif /* !NANO_TINY */
|
|
|
|
{
|
|
|
|
free(s);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the symbol that corresponds to the given menu name. */
|
|
|
|
int name_to_menu(const char *name)
|
|
|
|
{
|
|
|
|
int index = -1;
|
|
|
|
|
|
|
|
while (++index < NUMBER_OF_MENUS)
|
2019-12-13 18:03:38 +00:00
|
|
|
if (strcmp(name, menunames[index]) == 0)
|
2019-12-13 17:54:53 +00:00
|
|
|
return menusymbols[index];
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the name that corresponds to the given menu symbol. */
|
|
|
|
char *menu_to_name(int menu)
|
|
|
|
{
|
|
|
|
int index = -1;
|
|
|
|
|
|
|
|
while (++index < NUMBER_OF_MENUS)
|
|
|
|
if (menusymbols[index] == menu)
|
|
|
|
return menunames[index];
|
|
|
|
|
|
|
|
return "boooo";
|
|
|
|
}
|
|
|
|
|
2006-08-21 21:37:39 +00:00
|
|
|
/* Parse the next word from the string, null-terminate it, and return
|
|
|
|
* a pointer to the first character after the null terminator. The
|
|
|
|
* returned pointer will point to '\0' if we hit the end of the line. */
|
2002-08-21 16:10:37 +00:00
|
|
|
char *parse_next_word(char *ptr)
|
2001-04-18 04:28:54 +00:00
|
|
|
{
|
2017-12-29 18:27:33 +00:00
|
|
|
while (!isblank((unsigned char)*ptr) && *ptr != '\0')
|
|
|
|
ptr++;
|
2002-01-19 16:52:34 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (*ptr == '\0')
|
|
|
|
return ptr;
|
2002-01-19 16:52:34 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Null-terminate and advance ptr. */
|
|
|
|
*ptr++ = '\0';
|
2002-01-19 16:52:34 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
while (isblank((unsigned char)*ptr))
|
|
|
|
ptr++;
|
2002-01-19 16:52:34 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
return ptr;
|
2002-01-19 16:52:34 +00:00
|
|
|
}
|
2002-01-18 21:54:35 +00:00
|
|
|
|
2006-01-06 21:51:10 +00:00
|
|
|
/* Parse an argument, with optional quotes, after a keyword that takes
|
|
|
|
* one. If the next word starts with a ", we say that it ends with the
|
|
|
|
* last " of the line. Otherwise, we interpret it as usual, so that the
|
|
|
|
* arguments can contain "'s too. */
|
2002-08-21 16:10:37 +00:00
|
|
|
char *parse_argument(char *ptr)
|
|
|
|
{
|
2017-12-29 18:27:33 +00:00
|
|
|
const char *ptr_save = ptr;
|
|
|
|
char *last_quote = NULL;
|
|
|
|
|
|
|
|
if (*ptr != '"')
|
|
|
|
return parse_next_word(ptr);
|
|
|
|
|
2018-01-19 17:05:24 +00:00
|
|
|
while (*ptr != '\0') {
|
|
|
|
if (*++ptr == '"')
|
2017-12-29 18:27:33 +00:00
|
|
|
last_quote = ptr;
|
2018-01-19 17:05:24 +00:00
|
|
|
}
|
2017-12-29 18:27:33 +00:00
|
|
|
|
|
|
|
if (last_quote == NULL) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Argument '%s' has an unterminated \""), ptr_save);
|
2018-01-19 17:05:24 +00:00
|
|
|
return NULL;
|
2017-12-29 18:27:33 +00:00
|
|
|
}
|
2018-01-19 17:05:24 +00:00
|
|
|
|
|
|
|
*last_quote = '\0';
|
|
|
|
ptr = last_quote + 1;
|
|
|
|
|
|
|
|
while (isblank((unsigned char)*ptr))
|
|
|
|
ptr++;
|
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
return ptr;
|
2002-07-19 01:08:59 +00:00
|
|
|
}
|
|
|
|
|
2017-11-01 18:45:33 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2020-03-03 15:41:21 +00:00
|
|
|
/* Advance over one regular expression in the line starting at ptr,
|
|
|
|
* null-terminate it, and return a pointer to the succeeding text. */
|
2002-09-06 20:35:28 +00:00
|
|
|
char *parse_next_regex(char *ptr)
|
|
|
|
{
|
2020-03-03 16:37:13 +00:00
|
|
|
char *starting_point = ptr;
|
|
|
|
|
2020-03-03 15:21:47 +00:00
|
|
|
if (*(ptr - 1) != '"') {
|
|
|
|
jot_error(N_("Regex strings must begin and end with a \" character"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-03 15:41:21 +00:00
|
|
|
/* Continue until the end of the line, or until a double quote followed
|
|
|
|
* by end-of-line or a blank. */
|
2017-12-29 18:27:33 +00:00
|
|
|
while (*ptr != '\0' && (*ptr != '"' ||
|
2020-03-03 15:41:21 +00:00
|
|
|
(ptr[1] != '\0' && !isblank((unsigned char)ptr[1]))))
|
2017-12-29 18:27:33 +00:00
|
|
|
ptr++;
|
2002-09-06 20:35:28 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (*ptr == '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Regex strings must begin and end with a \" character"));
|
2017-12-29 18:27:33 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2002-09-06 20:35:28 +00:00
|
|
|
|
2020-03-03 16:37:13 +00:00
|
|
|
if (ptr == starting_point) {
|
|
|
|
jot_error(N_("Empty regex string"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-03 15:41:21 +00:00
|
|
|
/* Null-terminate the regex and skip until the next non-blank. */
|
2017-12-29 18:27:33 +00:00
|
|
|
*ptr++ = '\0';
|
2002-09-06 20:35:28 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
while (isblank((unsigned char)*ptr))
|
|
|
|
ptr++;
|
2002-09-06 20:35:28 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
return ptr;
|
2002-09-06 20:35:28 +00:00
|
|
|
}
|
|
|
|
|
2019-06-05 11:00:35 +00:00
|
|
|
/* Compile the given regular expression and store the result in packed (when
|
|
|
|
* this pointer is not NULL). Return TRUE when the expression is valid. */
|
|
|
|
bool compile(const char *expression, int rex_flags, regex_t **packed)
|
2003-02-03 02:56:44 +00:00
|
|
|
{
|
2019-06-05 11:00:35 +00:00
|
|
|
regex_t *compiled = nmalloc(sizeof(regex_t));
|
2019-06-05 12:47:46 +00:00
|
|
|
int outcome = regcomp(compiled, expression, rex_flags);
|
2003-02-03 02:56:44 +00:00
|
|
|
|
2019-06-05 12:47:46 +00:00
|
|
|
if (outcome != 0) {
|
|
|
|
size_t length = regerror(outcome, compiled, NULL, 0);
|
2020-08-30 02:57:45 +00:00
|
|
|
char *message = nmalloc(length);
|
2003-02-03 02:56:44 +00:00
|
|
|
|
2019-06-05 12:47:46 +00:00
|
|
|
regerror(outcome, compiled, message, length);
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Bad regex \"%s\": %s"), expression, message);
|
2019-06-05 12:47:46 +00:00
|
|
|
free(message);
|
2005-03-04 15:09:55 +00:00
|
|
|
|
2019-06-05 11:00:35 +00:00
|
|
|
regfree(compiled);
|
|
|
|
free(compiled);
|
2019-06-03 23:37:02 +00:00
|
|
|
} else
|
2019-06-05 11:00:35 +00:00
|
|
|
*packed = compiled;
|
2019-06-03 23:37:02 +00:00
|
|
|
|
2019-06-05 12:47:46 +00:00
|
|
|
return (outcome == 0);
|
2003-02-03 02:56:44 +00:00
|
|
|
}
|
|
|
|
|
2016-03-11 16:39:27 +00:00
|
|
|
/* Parse the next syntax name and its possible extension regexes from the
|
|
|
|
* line at ptr, and add it to the global linked list of color syntaxes. */
|
2019-06-14 08:46:50 +00:00
|
|
|
void begin_new_syntax(char *ptr)
|
2002-05-04 03:47:33 +00:00
|
|
|
{
|
2018-02-07 10:18:38 +00:00
|
|
|
char *nameptr = ptr;
|
2002-05-04 03:47:33 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Check that the syntax name is not empty. */
|
|
|
|
if (*ptr == '\0' || (*ptr == '"' &&
|
|
|
|
(*(ptr + 1) == '\0' || *(ptr + 1) == '"'))) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Missing syntax name"));
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2002-05-04 03:47:33 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
ptr = parse_next_word(ptr);
|
2016-03-09 20:28:50 +00:00
|
|
|
|
2018-02-07 10:25:46 +00:00
|
|
|
/* Check that quotes around the name are either paired or absent. */
|
2018-02-07 10:18:38 +00:00
|
|
|
if ((*nameptr == '\x22') ^ (nameptr[strlen(nameptr) - 1] == '\x22')) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Unpaired quote in syntax name"));
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-03-10 20:55:11 +00:00
|
|
|
|
2018-02-07 10:18:38 +00:00
|
|
|
/* If the name is quoted, strip the quotes. */
|
|
|
|
if (*nameptr == '\x22') {
|
|
|
|
nameptr++;
|
|
|
|
nameptr[strlen(nameptr) - 1] = '\0';
|
|
|
|
}
|
2002-05-04 03:47:33 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Redefining the "none" syntax is not allowed. */
|
|
|
|
if (strcmp(nameptr, "none") == 0) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("The \"none\" syntax is reserved"));
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize a new syntax struct. */
|
2020-08-30 02:57:45 +00:00
|
|
|
live_syntax = nmalloc(sizeof(syntaxtype));
|
2019-10-13 10:24:27 +00:00
|
|
|
live_syntax->name = copy_of(nameptr);
|
2019-10-13 10:38:46 +00:00
|
|
|
live_syntax->filename = copy_of(nanorc);
|
2019-06-13 10:20:38 +00:00
|
|
|
live_syntax->lineno = lineno;
|
2019-05-31 10:23:47 +00:00
|
|
|
live_syntax->augmentations = NULL;
|
2017-12-29 18:27:33 +00:00
|
|
|
live_syntax->extensions = NULL;
|
|
|
|
live_syntax->headers = NULL;
|
|
|
|
live_syntax->magics = NULL;
|
|
|
|
live_syntax->linter = NULL;
|
2019-10-25 15:17:48 +00:00
|
|
|
live_syntax->formatter = NULL;
|
2018-10-29 19:40:55 +00:00
|
|
|
live_syntax->tab = NULL;
|
2017-07-02 06:46:59 +00:00
|
|
|
#ifdef ENABLE_COMMENT
|
2019-10-13 10:24:27 +00:00
|
|
|
live_syntax->comment = copy_of(GENERAL_COMMENT_CHARACTER);
|
2017-07-02 06:46:59 +00:00
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
live_syntax->color = NULL;
|
|
|
|
live_syntax->nmultis = 0;
|
2016-03-10 20:06:01 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Hook the new syntax in at the top of the list. */
|
|
|
|
live_syntax->next = syntaxes;
|
|
|
|
syntaxes = live_syntax;
|
2005-07-29 21:42:08 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
opensyntax = TRUE;
|
2019-06-15 17:34:23 +00:00
|
|
|
seen_color_command = FALSE;
|
2016-02-28 20:38:14 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* The default syntax should have no associated extensions. */
|
|
|
|
if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("The \"default\" syntax does not accept extensions"));
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-08-01 04:23:29 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* If there seem to be extension regexes, pick them up. */
|
|
|
|
if (*ptr != '\0')
|
|
|
|
grab_and_store("extension", ptr, &live_syntax->extensions);
|
2011-02-13 04:23:10 +00:00
|
|
|
}
|
2017-11-01 18:45:33 +00:00
|
|
|
#endif /* ENABLE_COLOR */
|
2002-05-04 03:47:33 +00:00
|
|
|
|
2019-06-15 17:34:23 +00:00
|
|
|
/* Verify that a syntax definition contains at least one color command. */
|
|
|
|
void check_for_nonempty_syntax(void)
|
|
|
|
{
|
|
|
|
#ifdef ENABLE_COLOR
|
2019-07-09 02:54:04 +00:00
|
|
|
if (opensyntax && !seen_color_command) {
|
|
|
|
size_t current_lineno = lineno;
|
|
|
|
|
|
|
|
lineno = live_syntax->lineno;
|
2019-06-15 17:34:23 +00:00
|
|
|
jot_error(N_("Syntax \"%s\" has no color commands"), live_syntax->name);
|
2019-07-09 02:54:04 +00:00
|
|
|
lineno = current_lineno;
|
|
|
|
}
|
2019-06-15 17:34:23 +00:00
|
|
|
|
|
|
|
opensyntax = FALSE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-03-01 10:16:59 +00:00
|
|
|
/* Return TRUE when the given function is present in almost all menus. */
|
2017-07-02 04:07:54 +00:00
|
|
|
bool is_universal(void (*func)(void))
|
2014-06-27 16:14:52 +00:00
|
|
|
{
|
2018-03-01 10:16:59 +00:00
|
|
|
return (func == do_left || func == do_right ||
|
2017-12-29 18:27:33 +00:00
|
|
|
func == do_home || func == do_end ||
|
2017-06-04 09:05:08 +00:00
|
|
|
#ifndef NANO_TINY
|
2020-03-11 18:43:03 +00:00
|
|
|
func == to_prev_word || func == to_next_word ||
|
2017-06-04 09:05:08 +00:00
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
func == do_delete || func == do_backspace ||
|
2019-05-03 17:51:15 +00:00
|
|
|
func == cut_text || func == paste_text ||
|
2018-03-01 10:16:59 +00:00
|
|
|
func == do_tab || func == do_enter || func == do_verbatim_input);
|
2014-06-27 16:14:52 +00:00
|
|
|
}
|
|
|
|
|
2014-04-08 11:43:50 +00:00
|
|
|
/* Bind or unbind a key combo, to or from a function. */
|
2014-04-08 11:22:41 +00:00
|
|
|
void parse_binding(char *ptr, bool dobind)
|
2008-03-05 07:34:01 +00:00
|
|
|
{
|
2017-12-29 18:27:33 +00:00
|
|
|
char *keyptr = NULL, *keycopy = NULL, *funcptr = NULL, *menuptr = NULL;
|
2020-01-20 12:03:28 +00:00
|
|
|
int keycode, menu, mask = 0;
|
2020-01-20 16:22:35 +00:00
|
|
|
keystruct *newsc = NULL;
|
2008-03-05 07:34:01 +00:00
|
|
|
|
2019-06-15 17:34:23 +00:00
|
|
|
check_for_nonempty_syntax();
|
2019-06-15 13:07:57 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (*ptr == '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Missing key name"));
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
2014-04-08 11:43:50 +00:00
|
|
|
}
|
2017-12-29 18:27:33 +00:00
|
|
|
|
|
|
|
keyptr = ptr;
|
2014-04-08 11:22:41 +00:00
|
|
|
ptr = parse_next_word(ptr);
|
2019-10-13 10:24:27 +00:00
|
|
|
keycopy = copy_of(keyptr);
|
2008-03-05 07:34:01 +00:00
|
|
|
|
2020-01-22 17:55:36 +00:00
|
|
|
/* Uppercase either the second or the first character of the key name. */
|
|
|
|
if (keycopy[0] == '^')
|
|
|
|
keycopy[1] = toupper((unsigned char)keycopy[1]);
|
|
|
|
else
|
|
|
|
keycopy[0] = toupper((unsigned char)keycopy[0]);
|
2008-03-05 07:34:01 +00:00
|
|
|
|
2020-01-21 08:41:42 +00:00
|
|
|
/* Verify that the key name is not too short, to allow the next call. */
|
|
|
|
if (keycopy[1] == '\0' || (keycopy[0] == 'M' && keycopy[2] == '\0')) {
|
|
|
|
jot_error(N_("Key name %s is invalid"), keycopy);
|
2017-12-29 18:27:33 +00:00
|
|
|
goto free_things;
|
2020-01-20 12:03:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
keycode = keycode_from_string(keycopy);
|
|
|
|
|
|
|
|
if (keycode < 0) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Key name %s is invalid"), keycopy);
|
2017-12-29 18:27:33 +00:00
|
|
|
goto free_things;
|
|
|
|
}
|
2014-04-21 18:12:29 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (dobind) {
|
|
|
|
funcptr = ptr;
|
2018-01-20 12:01:43 +00:00
|
|
|
ptr = parse_argument(ptr);
|
2014-06-27 16:14:52 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (funcptr[0] == '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Must specify a function to bind the key to"));
|
2017-12-29 18:27:33 +00:00
|
|
|
goto free_things;
|
2018-05-24 18:07:39 +00:00
|
|
|
} else if (ptr == NULL)
|
|
|
|
goto free_things;
|
2017-12-29 18:27:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
menuptr = ptr;
|
|
|
|
ptr = parse_next_word(ptr);
|
|
|
|
|
|
|
|
if (menuptr[0] == '\0') {
|
|
|
|
/* TRANSLATORS: Do not translate the word "all". */
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Must specify a menu (or \"all\") "
|
|
|
|
"in which to bind/unbind the key"));
|
2017-12-29 18:27:33 +00:00
|
|
|
goto free_things;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dobind) {
|
2018-01-20 12:01:43 +00:00
|
|
|
/* If the thing to bind starts with a double quote, it is a string,
|
|
|
|
* otherwise it is the name of a function. */
|
|
|
|
if (*funcptr == '"') {
|
2019-04-03 15:34:05 +00:00
|
|
|
newsc = nmalloc(sizeof(keystruct));
|
2018-03-18 18:17:56 +00:00
|
|
|
newsc->func = (functionptrtype)implant;
|
2019-10-13 10:24:27 +00:00
|
|
|
newsc->expansion = copy_of(funcptr + 1);
|
2018-02-14 16:47:08 +00:00
|
|
|
#ifndef NANO_TINY
|
2018-01-20 12:01:43 +00:00
|
|
|
newsc->toggle = 0;
|
2018-02-14 16:47:08 +00:00
|
|
|
#endif
|
2018-01-20 12:01:43 +00:00
|
|
|
} else
|
2018-08-28 10:31:53 +00:00
|
|
|
newsc = strtosc(funcptr);
|
2018-01-20 12:01:43 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (newsc == NULL) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Cannot map name \"%s\" to a function"), funcptr);
|
2017-12-29 18:27:33 +00:00
|
|
|
goto free_things;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-11 07:51:33 +00:00
|
|
|
menu = name_to_menu(menuptr);
|
2017-12-29 18:27:33 +00:00
|
|
|
if (menu < 1) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Cannot map name \"%s\" to a menu"), menuptr);
|
2017-12-29 18:27:33 +00:00
|
|
|
goto free_things;
|
|
|
|
}
|
|
|
|
|
2018-12-18 18:07:28 +00:00
|
|
|
/* Wipe the given shortcut from the given menu. */
|
2020-01-20 16:22:35 +00:00
|
|
|
for (keystruct *s = sclist; s != NULL; s = s->next)
|
2020-01-20 12:34:32 +00:00
|
|
|
if ((s->menus & menu) && s->keycode == keycode)
|
2018-12-18 18:07:28 +00:00
|
|
|
s->menus &= ~menu;
|
2018-10-24 16:05:35 +00:00
|
|
|
|
2018-12-18 18:18:10 +00:00
|
|
|
/* When unbinding, we are done now. */
|
|
|
|
if (!dobind)
|
|
|
|
goto free_things;
|
2018-10-24 16:05:35 +00:00
|
|
|
|
2020-01-20 17:57:25 +00:00
|
|
|
/* Limit the given menu to those where the function exists;
|
bindings: allow toggling the help lines at several prompts and in browser
Now the help lines can be toggled not only while editing, but also at
the Read (^R), Write (^O), Execute (^T), Search (^W), Replace (M-R),
Goto (^/), and Yesno prompts, and also in the file browser and when
searching for a file name. The help lines cannot be toggled in the
help viewer, nor when searching in a help text, nor in the linter,
as these three things force the help lines to be on.
Furthermore, the 'nohelp' function can be rebound in all relevant
menus (default binding: M-X).
This fulfills https://savannah.gnu.org/bugs/?58471.
2020-05-31 18:04:15 +00:00
|
|
|
* first handle five special cases, then the general case. */
|
2020-01-20 16:36:31 +00:00
|
|
|
if (is_universal(newsc->func))
|
2020-01-20 17:57:25 +00:00
|
|
|
menu &= MMOST|MBROWSER;
|
2016-09-01 07:36:47 +00:00
|
|
|
#ifndef NANO_TINY
|
2021-11-08 15:16:35 +00:00
|
|
|
else if (newsc->func == do_toggle && newsc->toggle == NO_HELP)
|
bindings: allow toggling the help lines at several prompts and in browser
Now the help lines can be toggled not only while editing, but also at
the Read (^R), Write (^O), Execute (^T), Search (^W), Replace (M-R),
Goto (^/), and Yesno prompts, and also in the file browser and when
searching for a file name. The help lines cannot be toggled in the
help viewer, nor when searching in a help text, nor in the linter,
as these three things force the help lines to be on.
Furthermore, the 'nohelp' function can be rebound in all relevant
menus (default binding: M-X).
This fulfills https://savannah.gnu.org/bugs/?58471.
2020-05-31 18:04:15 +00:00
|
|
|
menu &= (MMOST|MBROWSER|MYESNO) & ~MFINDINHELP;
|
2021-11-08 15:16:35 +00:00
|
|
|
else if (newsc->func == do_toggle)
|
2020-01-20 17:57:25 +00:00
|
|
|
menu &= MMAIN;
|
2016-09-01 07:36:47 +00:00
|
|
|
#endif
|
2020-05-31 17:09:48 +00:00
|
|
|
else if (newsc->func == full_refresh)
|
|
|
|
menu &= MMOST|MBROWSER|MHELP|MYESNO;
|
2020-01-20 16:36:31 +00:00
|
|
|
else if (newsc->func == (functionptrtype)implant)
|
2020-01-20 17:57:25 +00:00
|
|
|
menu &= MMOST|MBROWSER|MHELP;
|
2020-01-20 16:36:31 +00:00
|
|
|
else {
|
|
|
|
/* Tally up the menus where the function exists. */
|
|
|
|
for (funcstruct *f = allfuncs; f != NULL; f = f->next)
|
|
|
|
if (f->func == newsc->func)
|
2020-01-20 17:57:25 +00:00
|
|
|
mask |= f->menus;
|
2019-10-13 16:51:15 +00:00
|
|
|
|
2020-01-20 17:57:25 +00:00
|
|
|
menu &= mask;
|
|
|
|
}
|
2014-06-27 16:14:52 +00:00
|
|
|
|
2018-10-24 16:12:06 +00:00
|
|
|
if (!menu) {
|
2019-03-31 18:05:30 +00:00
|
|
|
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE))
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Function '%s' does not exist in menu '%s'"),
|
2018-10-24 16:12:06 +00:00
|
|
|
funcptr, menuptr);
|
|
|
|
goto free_things;
|
|
|
|
}
|
2014-06-27 16:14:52 +00:00
|
|
|
|
2018-10-24 16:12:06 +00:00
|
|
|
newsc->menus = menu;
|
2020-01-22 12:34:17 +00:00
|
|
|
newsc->keystr = keycopy;
|
|
|
|
newsc->keycode = keycode;
|
2008-03-05 07:34:01 +00:00
|
|
|
|
2020-08-04 15:11:05 +00:00
|
|
|
/* Disallow rebinding <Esc> (^[). */
|
|
|
|
if (newsc->keycode == ESC_CODE) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Keystroke %s may not be rebound"), keycopy);
|
2018-12-18 18:18:10 +00:00
|
|
|
free_things:
|
|
|
|
free(keycopy);
|
|
|
|
free(newsc);
|
|
|
|
return;
|
2018-10-24 16:12:06 +00:00
|
|
|
}
|
2009-11-21 16:26:59 +00:00
|
|
|
|
2016-09-01 07:36:47 +00:00
|
|
|
#ifndef NANO_TINY
|
2018-10-24 16:12:06 +00:00
|
|
|
/* If this is a toggle, find and copy its sequence number. */
|
2021-11-08 15:16:35 +00:00
|
|
|
if (newsc->func == do_toggle) {
|
2020-01-20 16:22:35 +00:00
|
|
|
for (keystruct *s = sclist; s != NULL; s = s->next)
|
2021-11-08 15:16:35 +00:00
|
|
|
if (s->func == do_toggle && s->toggle == newsc->toggle)
|
2018-10-24 16:12:06 +00:00
|
|
|
newsc->ordinal = s->ordinal;
|
|
|
|
} else
|
|
|
|
newsc->ordinal = 0;
|
2016-09-01 07:36:47 +00:00
|
|
|
#endif
|
2018-10-24 16:12:06 +00:00
|
|
|
/* Add the new shortcut at the start of the list. */
|
|
|
|
newsc->next = sclist;
|
|
|
|
sclist = newsc;
|
2009-11-21 16:26:59 +00:00
|
|
|
}
|
|
|
|
|
2017-10-27 21:15:06 +00:00
|
|
|
/* Verify that the given file exists, is not a folder nor a device. */
|
2016-11-27 16:27:04 +00:00
|
|
|
bool is_good_file(char *file)
|
|
|
|
{
|
2017-12-29 18:27:33 +00:00
|
|
|
struct stat rcinfo;
|
|
|
|
|
|
|
|
/* First check that the file exists and is readable. */
|
|
|
|
if (access(file, R_OK) != 0)
|
|
|
|
return FALSE;
|
|
|
|
|
2018-05-27 16:35:52 +00:00
|
|
|
/* If the thing exists, it may be neither a directory nor a device. */
|
2017-12-29 18:27:33 +00:00
|
|
|
if (stat(file, &rcinfo) != -1 && (S_ISDIR(rcinfo.st_mode) ||
|
|
|
|
S_ISCHR(rcinfo.st_mode) || S_ISBLK(rcinfo.st_mode))) {
|
2019-06-15 12:11:23 +00:00
|
|
|
jot_error(S_ISDIR(rcinfo.st_mode) ? N_("\"%s\" is a directory") :
|
|
|
|
N_("\"%s\" is a device file"), file);
|
2017-12-29 18:27:33 +00:00
|
|
|
return FALSE;
|
|
|
|
} else
|
|
|
|
return TRUE;
|
2016-11-27 16:27:04 +00:00
|
|
|
}
|
|
|
|
|
2017-11-01 18:45:33 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2019-08-17 11:28:47 +00:00
|
|
|
/* Partially parse the syntaxes in the given file, or (when syntax
|
|
|
|
* is not NULL) fully parse one specific syntax from the file . */
|
2019-05-14 00:01:59 +00:00
|
|
|
void parse_one_include(char *file, syntaxtype *syntax)
|
2006-04-13 02:43:54 +00:00
|
|
|
{
|
2019-08-14 20:37:40 +00:00
|
|
|
char *was_nanorc = nanorc;
|
|
|
|
size_t was_lineno = lineno;
|
2019-05-31 10:53:36 +00:00
|
|
|
augmentstruct *extra;
|
2017-12-29 18:27:33 +00:00
|
|
|
FILE *rcstream;
|
2006-04-13 02:43:54 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Don't open directories, character files, or block files. */
|
|
|
|
if (!is_good_file(file))
|
|
|
|
return;
|
2006-04-13 02:43:54 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
rcstream = fopen(file, "rb");
|
2016-11-26 16:41:31 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (rcstream == NULL) {
|
2019-06-15 12:11:23 +00:00
|
|
|
jot_error(N_("Error reading %s: %s"), file, strerror(errno));
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-04-13 02:43:54 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Use the name and line number position of the included syntax file
|
|
|
|
* while parsing it, so we can know where any errors in it are. */
|
|
|
|
nanorc = file;
|
|
|
|
lineno = 0;
|
2006-04-13 02:43:54 +00:00
|
|
|
|
2019-05-14 00:01:59 +00:00
|
|
|
/* If this is the first pass, parse only the prologue. */
|
|
|
|
if (syntax == NULL) {
|
|
|
|
parse_rcfile(rcstream, TRUE, TRUE);
|
2019-08-14 20:37:40 +00:00
|
|
|
nanorc = was_nanorc;
|
|
|
|
lineno = was_lineno;
|
2019-05-14 00:01:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
live_syntax = syntax;
|
|
|
|
lastcolor = NULL;
|
|
|
|
|
2019-06-15 12:35:53 +00:00
|
|
|
/* Fully parse the given syntax (as it is about to be used). */
|
2019-05-14 00:01:59 +00:00
|
|
|
parse_rcfile(rcstream, TRUE, FALSE);
|
|
|
|
|
2019-05-31 10:53:36 +00:00
|
|
|
extra = syntax->augmentations;
|
2019-05-14 00:01:59 +00:00
|
|
|
|
|
|
|
/* Apply any stored extendsyntax commands. */
|
2019-05-31 10:53:36 +00:00
|
|
|
while (extra != NULL) {
|
|
|
|
char *keyword = extra->data;
|
2019-06-03 13:01:28 +00:00
|
|
|
char *therest = parse_next_word(extra->data);
|
2019-05-14 00:01:59 +00:00
|
|
|
|
2019-05-31 10:53:36 +00:00
|
|
|
nanorc = extra->filename;
|
|
|
|
lineno = extra->lineno;
|
2019-05-14 00:01:59 +00:00
|
|
|
|
2019-06-03 13:01:28 +00:00
|
|
|
if (!parse_syntax_commands(keyword, therest))
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Command \"%s\" not understood"), keyword);
|
2019-05-14 00:01:59 +00:00
|
|
|
|
2019-06-03 12:37:27 +00:00
|
|
|
extra = extra->next;
|
2019-05-14 00:01:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(syntax->filename);
|
|
|
|
syntax->filename = NULL;
|
2019-08-14 20:37:40 +00:00
|
|
|
|
|
|
|
nanorc = was_nanorc;
|
|
|
|
lineno = was_lineno;
|
2014-03-30 20:37:40 +00:00
|
|
|
}
|
|
|
|
|
2016-03-12 09:43:10 +00:00
|
|
|
/* Expand globs in the passed name, and parse the resultant files. */
|
|
|
|
void parse_includes(char *ptr)
|
2014-03-30 20:37:40 +00:00
|
|
|
{
|
2018-11-19 10:47:02 +00:00
|
|
|
char *pattern, *expanded;
|
2017-12-29 18:27:33 +00:00
|
|
|
glob_t files;
|
2018-11-19 11:00:18 +00:00
|
|
|
int result;
|
2017-12-29 18:27:33 +00:00
|
|
|
|
2019-08-18 08:52:03 +00:00
|
|
|
check_for_nonempty_syntax();
|
|
|
|
|
2018-11-19 10:47:02 +00:00
|
|
|
pattern = ptr;
|
|
|
|
if (*pattern == '"')
|
|
|
|
pattern++;
|
2017-12-29 18:27:33 +00:00
|
|
|
ptr = parse_argument(ptr);
|
|
|
|
|
2018-11-19 11:00:18 +00:00
|
|
|
/* Expand a tilde first, then try to match the globbing pattern. */
|
2018-11-19 10:47:02 +00:00
|
|
|
expanded = real_dir_from_tilde(pattern);
|
2019-04-02 18:40:48 +00:00
|
|
|
result = glob(expanded, GLOB_ERR, NULL, &files);
|
2017-12-29 18:27:33 +00:00
|
|
|
|
2018-11-19 11:00:18 +00:00
|
|
|
/* If there are matches, process each of them. Otherwise, only
|
|
|
|
* report an error if it's something other than zero matches. */
|
|
|
|
if (result == 0) {
|
2018-11-19 10:47:02 +00:00
|
|
|
for (size_t i = 0; i < files.gl_pathc; ++i)
|
2019-05-14 00:01:59 +00:00
|
|
|
parse_one_include(files.gl_pathv[i], NULL);
|
2018-11-19 11:00:18 +00:00
|
|
|
} else if (result != GLOB_NOMATCH)
|
2019-06-15 12:11:23 +00:00
|
|
|
jot_error(N_("Error expanding %s: %s"), pattern, strerror(errno));
|
2017-12-29 18:27:33 +00:00
|
|
|
|
|
|
|
globfree(&files);
|
|
|
|
free(expanded);
|
2006-04-13 02:43:54 +00:00
|
|
|
}
|
|
|
|
|
rcfile: support #rgb format for specifying colors in 256-color terminals
Most terminal emulators support a palette of 216 indexed colors:
the 6x6x6 color cube pioneered by Xterm. But as an index gives
little indication about what kind of color it produces, allow the
user to specify the color with three hex digits instead, one for
the level of red, green, and blue each, in the format #rgb.
One hex digit allows for sixteen values, but as there are only
six levels available, only 0, 4, 8, a, c, and e are significant
-- other values get reduced to the nearest lower one.
This fulfills https://savannah.gnu.org/bugs/?56445.
Requested-by: Peter Liscovius, Erik Lundin, Owen Maresh, Dave Lemonby
Signed-off-by: Brad Town <brad@bradtown.com>
2021-11-14 18:04:51 +00:00
|
|
|
/* Return the index of the color that is closest to the given RGB levels,
|
|
|
|
* assuming that the terminal uses the 6x6x6 color cube of xterm-256color. */
|
|
|
|
short closest_index_color(short r, short g, short b)
|
|
|
|
{
|
|
|
|
if (COLORS != 256)
|
|
|
|
return THE_DEFAULT;
|
|
|
|
|
|
|
|
/* Translation table, from 16 intended levels to 6 available levels. */
|
|
|
|
static const short level[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 };
|
|
|
|
|
|
|
|
return (36 * level[r] + 6 * level[g] + level[b] + 16);
|
|
|
|
}
|
|
|
|
|
2021-05-25 13:56:06 +00:00
|
|
|
#define COLORCOUNT 20
|
2021-05-25 13:28:02 +00:00
|
|
|
|
|
|
|
const char hues[COLORCOUNT][8] = { "red", "green", "blue",
|
|
|
|
"yellow", "cyan", "magenta",
|
|
|
|
"white", "black", "normal",
|
|
|
|
"pink", "purple", "mauve",
|
|
|
|
"lagoon", "mint", "lime",
|
2021-05-25 13:56:06 +00:00
|
|
|
"peach", "orange", "latte",
|
|
|
|
"grey", "gray" };
|
2021-05-25 13:28:02 +00:00
|
|
|
|
|
|
|
short indices[COLORCOUNT] = { COLOR_RED, COLOR_GREEN, COLOR_BLUE,
|
|
|
|
COLOR_YELLOW, COLOR_CYAN, COLOR_MAGENTA,
|
|
|
|
COLOR_WHITE, COLOR_BLACK, THE_DEFAULT,
|
2021-05-25 13:56:06 +00:00
|
|
|
204, 163, 134, 38, 48, 148, 215, 208, 137,
|
|
|
|
COLOR_BLACK + 8, COLOR_BLACK + 8 };
|
2020-06-09 15:05:42 +00:00
|
|
|
|
2020-06-08 09:55:31 +00:00
|
|
|
/* Return the short value corresponding to the given color name, and set
|
|
|
|
* vivid to TRUE for a lighter color, and thick for a heavier typeface. */
|
|
|
|
short color_to_short(const char *colorname, bool *vivid, bool *thick)
|
2006-05-28 19:00:16 +00:00
|
|
|
{
|
2020-08-19 14:17:07 +00:00
|
|
|
if (strncmp(colorname, "bright", 6) == 0 && colorname[6] != '\0') {
|
|
|
|
/* Prefix "bright" is deprecated; remove in 2024. */
|
2020-06-08 09:55:31 +00:00
|
|
|
*vivid = TRUE;
|
|
|
|
*thick = TRUE;
|
2017-12-29 18:27:33 +00:00
|
|
|
colorname += 6;
|
2020-08-19 14:17:07 +00:00
|
|
|
} else if (strncmp(colorname, "light", 5) == 0 && colorname[5] != '\0') {
|
2020-06-08 09:55:31 +00:00
|
|
|
*vivid = TRUE;
|
|
|
|
*thick = FALSE;
|
|
|
|
colorname += 5;
|
|
|
|
} else {
|
|
|
|
*vivid = FALSE;
|
|
|
|
*thick = FALSE;
|
|
|
|
}
|
2017-12-29 18:27:33 +00:00
|
|
|
|
rcfile: support #rgb format for specifying colors in 256-color terminals
Most terminal emulators support a palette of 216 indexed colors:
the 6x6x6 color cube pioneered by Xterm. But as an index gives
little indication about what kind of color it produces, allow the
user to specify the color with three hex digits instead, one for
the level of red, green, and blue each, in the format #rgb.
One hex digit allows for sixteen values, but as there are only
six levels available, only 0, 4, 8, a, c, and e are significant
-- other values get reduced to the nearest lower one.
This fulfills https://savannah.gnu.org/bugs/?56445.
Requested-by: Peter Liscovius, Erik Lundin, Owen Maresh, Dave Lemonby
Signed-off-by: Brad Town <brad@bradtown.com>
2021-11-14 18:04:51 +00:00
|
|
|
if (colorname[0] == '#' && strlen(colorname) == 4) {
|
|
|
|
unsigned short r, g, b;
|
|
|
|
|
|
|
|
if (*vivid) {
|
|
|
|
jot_error(N_("Color '%s' takes no prefix"), colorname);
|
|
|
|
return BAD_COLOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sscanf(colorname, "#%1hX%1hX%1hX", &r, &g, &b) == 3)
|
|
|
|
return closest_index_color(r, g, b);
|
|
|
|
}
|
|
|
|
|
2021-05-25 13:31:54 +00:00
|
|
|
for (int index = 0; index < COLORCOUNT; index++)
|
|
|
|
if (strcmp(colorname, hues[index]) == 0) {
|
2021-05-25 13:34:54 +00:00
|
|
|
if (index > 7 && *vivid) {
|
2021-05-25 13:31:54 +00:00
|
|
|
jot_error(N_("Color '%s' takes no prefix"), colorname);
|
|
|
|
return BAD_COLOR;
|
|
|
|
} else if (index > 8 && COLORS < 255)
|
|
|
|
return THE_DEFAULT;
|
|
|
|
else
|
|
|
|
return indices[index];
|
|
|
|
}
|
2017-12-29 18:27:33 +00:00
|
|
|
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Color \"%s\" not understood"), colorname);
|
2018-04-01 07:49:58 +00:00
|
|
|
return BAD_COLOR;
|
2006-05-28 19:00:16 +00:00
|
|
|
}
|
|
|
|
|
2018-03-30 08:25:39 +00:00
|
|
|
/* Parse the color name (or pair of color names) in the given string.
|
|
|
|
* Return FALSE when any color name is invalid; otherwise return TRUE. */
|
2020-03-03 10:27:37 +00:00
|
|
|
bool parse_combination(char *combostr, short *fg, short *bg, int *attributes)
|
2018-03-30 08:25:39 +00:00
|
|
|
{
|
2020-06-08 09:55:31 +00:00
|
|
|
bool vivid, thick;
|
2020-06-15 12:56:14 +00:00
|
|
|
char *comma;
|
2018-08-24 00:50:16 +00:00
|
|
|
|
|
|
|
*attributes = A_NORMAL;
|
2018-03-30 08:25:39 +00:00
|
|
|
|
2020-06-09 11:41:46 +00:00
|
|
|
if (strncmp(combostr, "bold", 4) == 0) {
|
2020-06-15 12:56:14 +00:00
|
|
|
*attributes |= A_BOLD;
|
2020-06-09 11:41:46 +00:00
|
|
|
if (combostr[4] != ',') {
|
|
|
|
jot_error(N_("An attribute requires a subsequent comma"));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
combostr += 5;
|
|
|
|
}
|
|
|
|
|
2020-06-15 12:48:17 +00:00
|
|
|
if (strncmp(combostr, "italic", 6) == 0) {
|
2020-06-22 09:15:27 +00:00
|
|
|
#ifdef A_ITALIC
|
2020-06-15 12:48:17 +00:00
|
|
|
*attributes |= A_ITALIC;
|
2020-06-22 09:15:27 +00:00
|
|
|
#endif
|
2020-06-15 12:48:17 +00:00
|
|
|
if (combostr[6] != ',') {
|
|
|
|
jot_error(N_("An attribute requires a subsequent comma"));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
combostr += 7;
|
|
|
|
}
|
|
|
|
|
2020-06-15 12:56:14 +00:00
|
|
|
comma = strchr(combostr, ',');
|
|
|
|
|
2020-06-17 14:50:17 +00:00
|
|
|
if (comma)
|
2018-03-30 08:25:39 +00:00
|
|
|
*comma = '\0';
|
|
|
|
|
2020-06-17 14:50:17 +00:00
|
|
|
if (!comma || comma > combostr) {
|
2020-06-08 09:55:31 +00:00
|
|
|
*fg = color_to_short(combostr, &vivid, &thick);
|
2018-04-01 07:49:58 +00:00
|
|
|
if (*fg == BAD_COLOR)
|
2018-03-30 08:25:39 +00:00
|
|
|
return FALSE;
|
2020-06-08 09:55:31 +00:00
|
|
|
if (vivid && !thick && COLORS > 8)
|
|
|
|
*fg += 8;
|
|
|
|
else if (vivid)
|
2020-06-09 11:41:46 +00:00
|
|
|
*attributes |= A_BOLD;
|
2018-03-30 08:25:39 +00:00
|
|
|
} else
|
2020-06-17 14:54:48 +00:00
|
|
|
*fg = THE_DEFAULT;
|
2018-03-30 08:25:39 +00:00
|
|
|
|
2020-06-17 14:50:17 +00:00
|
|
|
if (comma) {
|
|
|
|
*bg = color_to_short(comma + 1, &vivid, &thick);
|
|
|
|
if (*bg == BAD_COLOR)
|
|
|
|
return FALSE;
|
|
|
|
if (vivid && COLORS > 8)
|
|
|
|
*bg += 8;
|
|
|
|
} else
|
2020-06-17 14:54:48 +00:00
|
|
|
*bg = THE_DEFAULT;
|
2020-06-17 14:50:17 +00:00
|
|
|
|
2018-03-30 08:25:39 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-03-03 10:16:51 +00:00
|
|
|
/* Parse the color specification that starts at ptr, and then the one or more
|
|
|
|
* regexes that follow it. For each valid regex (or start=/end= regex pair),
|
|
|
|
* add a rule to the current syntax. */
|
|
|
|
void parse_rule(char *ptr, int rex_flags)
|
2001-11-29 02:42:27 +00:00
|
|
|
{
|
2020-03-03 10:27:37 +00:00
|
|
|
char *names, *regexstring;
|
2017-12-29 18:27:33 +00:00
|
|
|
short fg, bg;
|
2018-08-24 00:50:16 +00:00
|
|
|
int attributes;
|
2017-12-29 18:27:33 +00:00
|
|
|
|
|
|
|
if (*ptr == '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Missing color name"));
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-11-29 02:42:27 +00:00
|
|
|
|
2020-03-03 10:27:37 +00:00
|
|
|
names = ptr;
|
2017-12-29 18:27:33 +00:00
|
|
|
ptr = parse_next_word(ptr);
|
2020-03-04 15:23:47 +00:00
|
|
|
|
2020-03-03 10:27:37 +00:00
|
|
|
if (!parse_combination(names, &fg, &bg, &attributes))
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
2003-02-07 00:19:05 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (*ptr == '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Missing regex string after '%s' command"), "color");
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
2002-01-19 16:52:34 +00:00
|
|
|
}
|
|
|
|
|
2020-03-03 11:05:43 +00:00
|
|
|
while (*ptr != '\0') {
|
2020-03-04 15:08:34 +00:00
|
|
|
regex_t *start_rgx = NULL, *end_rgx = NULL;
|
|
|
|
/* Intermediate storage for compiled regular expressions. */
|
2017-12-29 18:27:33 +00:00
|
|
|
colortype *newcolor = NULL;
|
2020-03-04 15:23:47 +00:00
|
|
|
/* Container for compiled regex (pair) and the color it paints. */
|
2017-12-29 18:27:33 +00:00
|
|
|
bool expectend = FALSE;
|
2020-03-04 15:23:47 +00:00
|
|
|
/* Whether it is a start=/end= regex pair. */
|
2017-12-29 18:27:33 +00:00
|
|
|
|
2020-01-31 15:11:38 +00:00
|
|
|
if (strncmp(ptr, "start=", 6) == 0) {
|
2017-12-29 18:27:33 +00:00
|
|
|
ptr += 6;
|
|
|
|
expectend = TRUE;
|
|
|
|
}
|
2005-03-10 20:55:11 +00:00
|
|
|
|
2020-03-03 10:27:37 +00:00
|
|
|
regexstring = ++ptr;
|
2017-12-29 18:27:33 +00:00
|
|
|
ptr = parse_next_regex(ptr);
|
2020-03-03 15:21:47 +00:00
|
|
|
|
2020-03-04 15:23:47 +00:00
|
|
|
/* When there is no regex, or it is invalid, skip this line. */
|
|
|
|
if (ptr == NULL || !compile(regexstring, rex_flags, &start_rgx))
|
2020-03-03 18:42:40 +00:00
|
|
|
return;
|
2020-03-04 15:08:34 +00:00
|
|
|
|
|
|
|
if (expectend) {
|
|
|
|
if (strncmp(ptr, "end=", 4) != 0) {
|
|
|
|
jot_error(N_("\"start=\" requires a corresponding \"end=\""));
|
|
|
|
regfree(start_rgx);
|
|
|
|
free(start_rgx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
regexstring = ptr + 5;
|
|
|
|
ptr = parse_next_regex(ptr + 5);
|
|
|
|
|
|
|
|
/* When there is no valid end= regex, abandon the rule. */
|
|
|
|
if (ptr == NULL || !compile(regexstring, rex_flags, &end_rgx)) {
|
|
|
|
regfree(start_rgx);
|
|
|
|
free(start_rgx);
|
|
|
|
return;
|
|
|
|
}
|
2019-06-03 23:37:02 +00:00
|
|
|
}
|
2016-03-04 20:50:38 +00:00
|
|
|
|
2020-03-04 15:23:47 +00:00
|
|
|
/* Allocate a rule, fill in the data, and link it into the list. */
|
2020-08-30 02:57:45 +00:00
|
|
|
newcolor = nmalloc(sizeof(colortype));
|
2020-03-04 15:08:34 +00:00
|
|
|
|
|
|
|
newcolor->start = start_rgx;
|
|
|
|
newcolor->end = end_rgx;
|
|
|
|
|
2020-03-03 18:46:46 +00:00
|
|
|
newcolor->fg = fg;
|
|
|
|
newcolor->bg = bg;
|
|
|
|
newcolor->attributes = attributes;
|
2005-07-29 21:42:08 +00:00
|
|
|
|
2020-03-03 18:46:46 +00:00
|
|
|
if (lastcolor == NULL)
|
|
|
|
live_syntax->color = newcolor;
|
|
|
|
else
|
|
|
|
lastcolor->next = newcolor;
|
2002-07-19 01:08:59 +00:00
|
|
|
|
2020-03-03 18:46:46 +00:00
|
|
|
newcolor->next = NULL;
|
|
|
|
lastcolor = newcolor;
|
2005-03-10 20:55:11 +00:00
|
|
|
|
2020-03-04 15:23:47 +00:00
|
|
|
/* For a multiline rule, give it a number and increase the count. */
|
|
|
|
if (expectend) {
|
|
|
|
newcolor->id = live_syntax->nmultis;
|
|
|
|
live_syntax->nmultis++;
|
|
|
|
}
|
2017-12-29 18:27:33 +00:00
|
|
|
}
|
2001-11-29 02:42:27 +00:00
|
|
|
}
|
2008-09-21 23:02:30 +00:00
|
|
|
|
2018-01-15 12:06:35 +00:00
|
|
|
/* Parse the argument of an interface color option. */
|
2018-01-12 10:47:07 +00:00
|
|
|
colortype *parse_interface_color(char *combostr)
|
|
|
|
{
|
2018-01-15 12:06:35 +00:00
|
|
|
colortype *trio = nmalloc(sizeof(colortype));
|
2018-01-12 10:47:07 +00:00
|
|
|
|
2020-10-21 09:21:11 +00:00
|
|
|
if (!parse_combination(combostr, &trio->fg, &trio->bg, &trio->attributes)) {
|
2018-01-15 12:06:35 +00:00
|
|
|
free(trio);
|
|
|
|
return NULL;
|
2020-10-21 09:21:11 +00:00
|
|
|
} else
|
|
|
|
return trio;
|
2018-01-12 10:47:07 +00:00
|
|
|
}
|
|
|
|
|
2016-02-28 15:16:27 +00:00
|
|
|
/* Read regex strings enclosed in double quotes from the line pointed at
|
|
|
|
* by ptr, and store them quoteless in the passed storage place. */
|
2016-03-10 11:00:59 +00:00
|
|
|
void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
|
2016-02-28 15:16:27 +00:00
|
|
|
{
|
2020-03-03 15:41:21 +00:00
|
|
|
regexlisttype *lastthing, *newthing;
|
|
|
|
const char *regexstring;
|
2008-09-21 23:02:30 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (!opensyntax) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("A '%s' command requires a preceding 'syntax' command"), kind);
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-03-10 09:46:21 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* The default syntax doesn't take any file matching stuff. */
|
|
|
|
if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("The \"default\" syntax does not accept '%s' regexes"), kind);
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-09-21 23:02:30 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (*ptr == '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Missing regex string after '%s' command"), kind);
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-09-21 23:02:30 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
lastthing = *storage;
|
2016-02-28 16:36:23 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* If there was an earlier command, go to the last of those regexes. */
|
|
|
|
while (lastthing != NULL && lastthing->next != NULL)
|
|
|
|
lastthing = lastthing->next;
|
2016-02-28 16:36:23 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Now gather any valid regexes and add them to the linked list. */
|
|
|
|
while (*ptr != '\0') {
|
2021-01-20 14:18:33 +00:00
|
|
|
regex_t *packed_rgx = NULL;
|
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
regexstring = ++ptr;
|
|
|
|
ptr = parse_next_regex(ptr);
|
2020-03-03 15:21:47 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (ptr == NULL)
|
|
|
|
return;
|
2008-09-21 23:02:30 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* If the regex string is malformed, skip it. */
|
2021-01-20 14:18:33 +00:00
|
|
|
if (!compile(regexstring, NANO_REG_EXTENDED | REG_NOSUB, &packed_rgx))
|
2017-12-29 18:27:33 +00:00
|
|
|
continue;
|
2008-09-21 23:02:30 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Copy the regex into a struct, and hook this in at the end. */
|
2020-08-30 02:57:45 +00:00
|
|
|
newthing = nmalloc(sizeof(regexlisttype));
|
2021-01-20 14:18:33 +00:00
|
|
|
newthing->one_rgx = packed_rgx;
|
2017-12-29 18:27:33 +00:00
|
|
|
newthing->next = NULL;
|
2008-09-21 23:02:30 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (lastthing == NULL)
|
|
|
|
*storage = newthing;
|
|
|
|
else
|
|
|
|
lastthing->next = newthing;
|
2016-02-28 15:47:37 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
lastthing = newthing;
|
|
|
|
}
|
2008-09-21 23:02:30 +00:00
|
|
|
}
|
2014-02-24 10:18:15 +00:00
|
|
|
|
2018-07-10 14:24:22 +00:00
|
|
|
/* Gather and store the string after a comment/linter command. */
|
2016-03-10 10:36:49 +00:00
|
|
|
void pick_up_name(const char *kind, char *ptr, char **storage)
|
2014-02-24 10:18:15 +00:00
|
|
|
{
|
2017-12-29 18:27:33 +00:00
|
|
|
if (*ptr == '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Missing argument after '%s'"), kind);
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-01-03 07:24:17 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* If the argument starts with a quote, find the terminating quote. */
|
|
|
|
if (*ptr == '"') {
|
2018-01-19 19:27:53 +00:00
|
|
|
char *look = ptr + strlen(ptr);
|
2017-07-01 11:25:11 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
while (*look != '"') {
|
2018-01-19 19:27:53 +00:00
|
|
|
if (--look == ptr) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Argument of '%s' lacks closing \""), kind);
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2018-01-19 19:27:53 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
*look = '\0';
|
2018-01-19 19:27:53 +00:00
|
|
|
ptr++;
|
2016-05-25 20:13:50 +00:00
|
|
|
}
|
2017-07-06 11:03:20 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
*storage = mallocstrcpy(*storage, ptr);
|
2015-01-03 07:24:17 +00:00
|
|
|
}
|
2019-06-17 07:59:15 +00:00
|
|
|
|
2020-05-24 10:26:24 +00:00
|
|
|
/* Handle the six syntax-only commands. */
|
2019-06-17 07:59:15 +00:00
|
|
|
bool parse_syntax_commands(char *keyword, char *ptr)
|
|
|
|
{
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(keyword, "color") == 0)
|
2020-03-03 10:16:51 +00:00
|
|
|
parse_rule(ptr, NANO_REG_EXTENDED);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(keyword, "icolor") == 0)
|
2020-03-03 10:16:51 +00:00
|
|
|
parse_rule(ptr, NANO_REG_EXTENDED | REG_ICASE);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(keyword, "comment") == 0) {
|
2019-06-17 07:59:15 +00:00
|
|
|
#ifdef ENABLE_COMMENT
|
|
|
|
pick_up_name("comment", ptr, &live_syntax->comment);
|
2018-10-29 19:40:55 +00:00
|
|
|
#endif
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(keyword, "tabgives") == 0) {
|
2018-10-29 19:40:55 +00:00
|
|
|
pick_up_name("tabgives", ptr, &live_syntax->tab);
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(keyword, "linter") == 0)
|
2019-06-17 07:59:15 +00:00
|
|
|
pick_up_name("linter", ptr, &live_syntax->linter);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(keyword, "formatter") == 0)
|
2019-10-25 15:17:48 +00:00
|
|
|
pick_up_name("formatter", ptr, &live_syntax->formatter);
|
2019-06-17 07:59:15 +00:00
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2017-11-01 18:45:33 +00:00
|
|
|
#endif /* ENABLE_COLOR */
|
2014-02-24 10:18:15 +00:00
|
|
|
|
2016-11-27 15:34:34 +00:00
|
|
|
/* Verify that the user has not unmapped every shortcut for a
|
|
|
|
* function that we consider 'vital' (such as "Exit"). */
|
2008-03-20 04:45:55 +00:00
|
|
|
static void check_vitals_mapped(void)
|
|
|
|
{
|
2019-12-15 14:25:10 +00:00
|
|
|
#define VITALS 4
|
|
|
|
void (*vitals[VITALS])(void) = { do_exit, do_exit, do_exit, do_cancel };
|
|
|
|
int inmenus[VITALS] = { MMAIN, MBROWSER, MHELP, MYESNO };
|
2017-12-29 18:27:33 +00:00
|
|
|
|
2019-12-15 14:30:48 +00:00
|
|
|
for (int v = 0; v < VITALS; v++) {
|
|
|
|
for (funcstruct *f = allfuncs; f != NULL; f = f->next) {
|
2018-02-24 18:31:11 +00:00
|
|
|
if (f->func == vitals[v] && f->menus & inmenus[v]) {
|
2020-06-29 09:25:57 +00:00
|
|
|
if (first_sc_for(inmenus[v], f->func) == NULL) {
|
|
|
|
jot_error(N_("No key is bound to function '%s' in menu '%s'. "
|
|
|
|
" Exiting.\n"), f->desc, menu_to_name(inmenus[v]));
|
|
|
|
die(_("If needed, use nano with the -I option "
|
|
|
|
"to adjust your nanorc settings.\n"));
|
|
|
|
} else
|
|
|
|
break;
|
2017-12-29 18:27:33 +00:00
|
|
|
}
|
2014-06-20 10:48:26 +00:00
|
|
|
}
|
|
|
|
}
|
2008-03-20 04:45:55 +00:00
|
|
|
}
|
|
|
|
|
2006-06-01 20:23:24 +00:00
|
|
|
/* Parse the rcfile, once it has been opened successfully at rcstream,
|
2019-06-14 08:46:50 +00:00
|
|
|
* and close it afterwards. If just_syntax is TRUE, allow the file to
|
2016-11-27 15:34:34 +00:00
|
|
|
* to contain only color syntax commands. */
|
2019-06-14 08:46:50 +00:00
|
|
|
void parse_rcfile(FILE *rcstream, bool just_syntax, bool intros_only)
|
2001-04-18 04:28:54 +00:00
|
|
|
{
|
2019-06-14 08:02:42 +00:00
|
|
|
char *buffer = NULL;
|
|
|
|
size_t size = 0;
|
2020-02-09 11:02:37 +00:00
|
|
|
ssize_t length;
|
2005-03-10 20:55:11 +00:00
|
|
|
|
2020-02-09 11:02:37 +00:00
|
|
|
while ((length = getline(&buffer, &size, rcstream)) > 0) {
|
2019-10-13 09:44:56 +00:00
|
|
|
char *ptr, *keyword, *option, *argument;
|
2019-10-12 09:14:56 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2019-10-07 07:10:06 +00:00
|
|
|
bool drop_open = FALSE;
|
2019-10-12 09:14:56 +00:00
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
int set = 0;
|
|
|
|
size_t i;
|
2005-03-10 20:55:11 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
lineno++;
|
2019-06-13 10:20:38 +00:00
|
|
|
|
2019-06-17 07:59:15 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2019-06-13 10:20:38 +00:00
|
|
|
/* If doing a full parse, skip to after the 'syntax' command. */
|
2019-06-14 08:46:50 +00:00
|
|
|
if (just_syntax && !intros_only && lineno <= live_syntax->lineno)
|
2019-06-13 10:20:38 +00:00
|
|
|
continue;
|
2019-06-17 07:59:15 +00:00
|
|
|
#endif
|
2020-02-09 10:41:56 +00:00
|
|
|
/* Strip the terminating newline and possibly a carriage return. */
|
2020-02-09 11:02:37 +00:00
|
|
|
if (buffer[length - 1] == '\n')
|
|
|
|
buffer[--length] = '\0';
|
2020-02-16 12:04:11 +00:00
|
|
|
if (length > 0 && buffer[length - 1] == '\r')
|
2020-02-09 11:02:37 +00:00
|
|
|
buffer[--length] = '\0';
|
2019-06-14 08:02:42 +00:00
|
|
|
|
|
|
|
ptr = buffer;
|
2017-12-29 18:27:33 +00:00
|
|
|
while (isblank((unsigned char)*ptr))
|
|
|
|
ptr++;
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2018-11-05 08:38:07 +00:00
|
|
|
/* If the line is empty or a comment, skip to next line. */
|
2017-12-29 18:27:33 +00:00
|
|
|
if (*ptr == '\0' || *ptr == '#')
|
|
|
|
continue;
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Otherwise, skip to the next space. */
|
|
|
|
keyword = ptr;
|
|
|
|
ptr = parse_next_word(ptr);
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2017-11-01 18:45:33 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Handle extending first... */
|
2019-12-12 18:06:48 +00:00
|
|
|
if (!just_syntax && strcmp(keyword, "extendsyntax") == 0) {
|
2019-06-03 13:51:07 +00:00
|
|
|
augmentstruct *newitem, *extra;
|
2017-12-29 18:27:33 +00:00
|
|
|
char *syntaxname = ptr;
|
2020-02-21 16:02:24 +00:00
|
|
|
syntaxtype *sntx;
|
2017-12-29 18:27:33 +00:00
|
|
|
|
2019-06-15 17:34:23 +00:00
|
|
|
check_for_nonempty_syntax();
|
2019-06-14 08:26:49 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
ptr = parse_next_word(ptr);
|
|
|
|
|
2020-02-21 16:02:24 +00:00
|
|
|
for (sntx = syntaxes; sntx != NULL; sntx = sntx->next)
|
|
|
|
if (!strcmp(sntx->name, syntaxname))
|
2017-12-29 18:27:33 +00:00
|
|
|
break;
|
|
|
|
|
2020-02-21 16:02:24 +00:00
|
|
|
if (sntx == NULL) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Could not find syntax \"%s\" to extend"), syntaxname);
|
2017-12-29 18:27:33 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-10-07 07:10:06 +00:00
|
|
|
keyword = ptr;
|
2019-10-13 10:38:46 +00:00
|
|
|
argument = copy_of(ptr);
|
2019-10-07 07:10:06 +00:00
|
|
|
ptr = parse_next_word(ptr);
|
|
|
|
|
|
|
|
/* File-matching commands need to be processed immediately;
|
|
|
|
* other commands are stored for possible later processing. */
|
|
|
|
if (strcmp(keyword, "header") == 0 || strcmp(keyword, "magic") == 0) {
|
|
|
|
free(argument);
|
2020-02-21 16:02:24 +00:00
|
|
|
live_syntax = sntx;
|
2019-10-07 07:10:06 +00:00
|
|
|
opensyntax = TRUE;
|
|
|
|
drop_open = TRUE;
|
|
|
|
} else {
|
2019-10-08 09:51:47 +00:00
|
|
|
newitem = nmalloc(sizeof(augmentstruct));;
|
2019-05-14 00:01:59 +00:00
|
|
|
|
2019-10-13 10:38:46 +00:00
|
|
|
newitem->filename = copy_of(nanorc);
|
2019-10-08 09:51:47 +00:00
|
|
|
newitem->lineno = lineno;
|
|
|
|
newitem->data = argument;
|
|
|
|
newitem->next = NULL;
|
|
|
|
|
2020-02-21 16:02:24 +00:00
|
|
|
if (sntx->augmentations != NULL) {
|
|
|
|
extra = sntx->augmentations;
|
2019-10-08 09:51:47 +00:00
|
|
|
while (extra->next != NULL)
|
|
|
|
extra = extra->next;
|
|
|
|
extra->next = newitem;
|
|
|
|
} else
|
2020-02-21 16:02:24 +00:00
|
|
|
sntx->augmentations = newitem;
|
2019-10-08 09:51:47 +00:00
|
|
|
|
|
|
|
continue;
|
2019-10-07 07:10:06 +00:00
|
|
|
}
|
2017-12-29 18:27:33 +00:00
|
|
|
}
|
2014-03-02 05:27:56 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
/* Try to parse the keyword. */
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(keyword, "syntax") == 0) {
|
2019-06-14 08:46:50 +00:00
|
|
|
if (intros_only) {
|
2019-06-15 17:34:23 +00:00
|
|
|
check_for_nonempty_syntax();
|
2019-06-14 08:46:50 +00:00
|
|
|
begin_new_syntax(ptr);
|
2019-06-13 10:20:38 +00:00
|
|
|
} else
|
|
|
|
break;
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(keyword, "header") == 0) {
|
2019-06-14 08:46:50 +00:00
|
|
|
if (intros_only)
|
2019-05-14 00:01:59 +00:00
|
|
|
grab_and_store("header", ptr, &live_syntax->headers);
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(keyword, "magic") == 0) {
|
2015-04-03 17:28:30 +00:00
|
|
|
#ifdef HAVE_LIBMAGIC
|
2019-06-14 08:46:50 +00:00
|
|
|
if (intros_only)
|
2019-05-14 00:01:59 +00:00
|
|
|
grab_and_store("magic", ptr, &live_syntax->magics);
|
2016-05-25 20:13:50 +00:00
|
|
|
#endif
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (just_syntax && (strcmp(keyword, "set") == 0 ||
|
|
|
|
strcmp(keyword, "unset") == 0 ||
|
|
|
|
strcmp(keyword, "bind") == 0 ||
|
|
|
|
strcmp(keyword, "unbind") == 0 ||
|
|
|
|
strcmp(keyword, "include") == 0 ||
|
|
|
|
strcmp(keyword, "extendsyntax") == 0)) {
|
2019-06-14 08:46:50 +00:00
|
|
|
if (intros_only)
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Command \"%s\" not allowed in included file"),
|
|
|
|
keyword);
|
2019-06-13 10:20:38 +00:00
|
|
|
else
|
|
|
|
break;
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (intros_only && (strcmp(keyword, "color") == 0 ||
|
|
|
|
strcmp(keyword, "icolor") == 0 ||
|
|
|
|
strcmp(keyword, "comment") == 0 ||
|
|
|
|
strcmp(keyword, "tabgives") == 0 ||
|
|
|
|
strcmp(keyword, "linter") == 0 ||
|
|
|
|
strcmp(keyword, "formatter") == 0)) {
|
2019-06-15 11:04:01 +00:00
|
|
|
if (!opensyntax)
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("A '%s' command requires a preceding "
|
|
|
|
"'syntax' command"), keyword);
|
2020-05-24 10:26:24 +00:00
|
|
|
if (strstr("icolor", keyword))
|
2019-06-15 11:04:01 +00:00
|
|
|
seen_color_command = TRUE;
|
2019-06-13 10:20:38 +00:00
|
|
|
continue;
|
|
|
|
} else if (parse_syntax_commands(keyword, ptr))
|
|
|
|
;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(keyword, "include") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
parse_includes(ptr);
|
|
|
|
else
|
2017-11-01 18:45:33 +00:00
|
|
|
#endif /* ENABLE_COLOR */
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(keyword, "set") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
set = 1;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(keyword, "unset") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
set = -1;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(keyword, "bind") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
parse_binding(ptr, TRUE);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(keyword, "unbind") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
parse_binding(ptr, FALSE);
|
2019-06-14 08:46:50 +00:00
|
|
|
else if (intros_only)
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Command \"%s\" not understood"), keyword);
|
2005-03-10 20:55:11 +00:00
|
|
|
|
2019-10-12 09:14:56 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2019-10-07 07:10:06 +00:00
|
|
|
if (drop_open)
|
|
|
|
opensyntax = FALSE;
|
2019-10-12 09:14:56 +00:00
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
if (set == 0)
|
|
|
|
continue;
|
2005-03-10 20:55:11 +00:00
|
|
|
|
2019-06-15 17:34:23 +00:00
|
|
|
check_for_nonempty_syntax();
|
2019-06-15 13:07:57 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (*ptr == '\0') {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Missing option"));
|
2017-12-29 18:27:33 +00:00
|
|
|
continue;
|
|
|
|
}
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
option = ptr;
|
|
|
|
ptr = parse_next_word(ptr);
|
2001-04-18 04:28:54 +00:00
|
|
|
|
2019-06-14 08:02:42 +00:00
|
|
|
/* Find the just parsed option name among the existing names. */
|
2017-12-29 18:27:33 +00:00
|
|
|
for (i = 0; rcopts[i].name != NULL; i++) {
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(option, rcopts[i].name) == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-03-14 17:14:35 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (rcopts[i].name == NULL) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Unknown option \"%s\""), option);
|
2017-12-29 18:27:33 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-03-14 17:14:35 +00:00
|
|
|
|
2019-06-13 17:55:43 +00:00
|
|
|
/* If the option has a flag, set it or unset it, as requested. */
|
|
|
|
if (rcopts[i].flag) {
|
|
|
|
if (set == 1)
|
|
|
|
SET(rcopts[i].flag);
|
2017-12-29 18:27:33 +00:00
|
|
|
else
|
2019-06-13 17:55:43 +00:00
|
|
|
UNSET(rcopts[i].flag);
|
2017-12-29 18:27:33 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-03-14 17:14:35 +00:00
|
|
|
|
2019-06-13 17:55:43 +00:00
|
|
|
/* An option that takes an argument cannot be unset. */
|
|
|
|
if (set == -1) {
|
2019-10-13 09:51:07 +00:00
|
|
|
jot_error(N_("Cannot unset option \"%s\""), option);
|
2017-12-29 18:27:33 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-03-14 17:14:35 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
if (*ptr == '\0') {
|
2019-10-13 09:51:07 +00:00
|
|
|
jot_error(N_("Option \"%s\" requires an argument"), option);
|
2017-12-29 18:27:33 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-03-14 17:14:35 +00:00
|
|
|
|
2019-10-13 09:44:56 +00:00
|
|
|
argument = ptr;
|
|
|
|
if (*argument == '"')
|
|
|
|
argument++;
|
2017-12-29 18:27:33 +00:00
|
|
|
ptr = parse_argument(ptr);
|
2016-03-14 17:14:35 +00:00
|
|
|
|
2018-07-08 08:40:22 +00:00
|
|
|
#ifdef ENABLE_UTF8
|
|
|
|
/* When in a UTF-8 locale, ignore arguments with invalid sequences. */
|
2019-10-13 09:44:56 +00:00
|
|
|
if (using_utf8() && mbstowcs(NULL, argument, 0) == (size_t)-1) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Argument is not a valid multibyte string"));
|
2017-12-29 18:27:33 +00:00
|
|
|
continue;
|
|
|
|
}
|
2018-07-08 08:40:22 +00:00
|
|
|
#endif
|
2017-11-01 18:45:33 +00:00
|
|
|
#ifdef ENABLE_COLOR
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(option, "titlecolor") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
color_combo[TITLE_BAR] = parse_interface_color(argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(option, "numbercolor") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
color_combo[LINE_NUMBER] = parse_interface_color(argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(option, "stripecolor") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
color_combo[GUIDE_STRIPE] = parse_interface_color(argument);
|
2020-08-28 16:40:10 +00:00
|
|
|
else if (strcmp(option, "scrollercolor") == 0)
|
|
|
|
color_combo[SCROLL_BAR] = parse_interface_color(argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(option, "selectedcolor") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
color_combo[SELECTED_TEXT] = parse_interface_color(argument);
|
2021-03-03 08:31:46 +00:00
|
|
|
else if (strcmp(option, "spotlightcolor") == 0)
|
2021-03-03 08:39:49 +00:00
|
|
|
color_combo[SPOTLIGHTED] = parse_interface_color(argument);
|
2021-06-07 10:10:23 +00:00
|
|
|
else if (strcmp(option, "minicolor") == 0)
|
|
|
|
color_combo[MINI_INFOBAR] = parse_interface_color(argument);
|
2020-12-06 14:49:35 +00:00
|
|
|
else if (strcmp(option, "promptcolor") == 0)
|
|
|
|
color_combo[PROMPT_BAR] = parse_interface_color(argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(option, "statuscolor") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
color_combo[STATUS_BAR] = parse_interface_color(argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(option, "errorcolor") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
color_combo[ERROR_MESSAGE] = parse_interface_color(argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(option, "keycolor") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
color_combo[KEY_COMBO] = parse_interface_color(argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(option, "functioncolor") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
color_combo[FUNCTION_TAG] = parse_interface_color(argument);
|
2017-12-29 18:27:33 +00:00
|
|
|
else
|
2014-05-03 18:24:45 +00:00
|
|
|
#endif
|
2017-10-29 20:08:07 +00:00
|
|
|
#ifdef ENABLE_OPERATINGDIR
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(option, "operatingdir") == 0)
|
2021-10-12 07:33:08 +00:00
|
|
|
operating_dir = mallocstrcpy(operating_dir, argument);
|
2017-12-29 18:27:33 +00:00
|
|
|
else
|
2002-07-19 01:08:59 +00:00
|
|
|
#endif
|
2017-10-31 16:39:30 +00:00
|
|
|
#ifdef ENABLED_WRAPORJUSTIFY
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(option, "fill") == 0) {
|
2019-10-13 09:44:56 +00:00
|
|
|
if (!parse_num(argument, &fill)) {
|
|
|
|
jot_error(N_("Requested fill size \"%s\" is invalid"), argument);
|
2018-10-22 23:01:23 +00:00
|
|
|
fill = -COLUMNS_FROM_EOL;
|
2019-01-25 18:25:39 +00:00
|
|
|
}
|
2017-12-29 18:27:33 +00:00
|
|
|
} else
|
2002-07-19 01:08:59 +00:00
|
|
|
#endif
|
2005-11-15 03:17:35 +00:00
|
|
|
#ifndef NANO_TINY
|
2020-10-03 09:58:43 +00:00
|
|
|
if (strcmp(option, "matchbrackets") == 0) {
|
2020-10-21 09:21:11 +00:00
|
|
|
if (has_blank_char(argument))
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Non-blank characters required"));
|
2020-10-21 09:21:11 +00:00
|
|
|
else if (mbstrlen(argument) % 2 != 0)
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Even number of characters required"));
|
2020-10-21 09:21:11 +00:00
|
|
|
else
|
2021-10-12 07:33:08 +00:00
|
|
|
matchbrackets = mallocstrcpy(matchbrackets, argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(option, "whitespace") == 0) {
|
2020-10-21 09:21:11 +00:00
|
|
|
if (mbstrlen(argument) != 2 || breadth(argument) != 2)
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Two single-column characters required"));
|
2020-10-21 09:21:11 +00:00
|
|
|
else {
|
2021-10-12 07:33:08 +00:00
|
|
|
whitespace = mallocstrcpy(whitespace, argument);
|
2019-06-09 15:36:29 +00:00
|
|
|
whitelen[0] = char_length(whitespace);
|
|
|
|
whitelen[1] = char_length(whitespace + whitelen[0]);
|
2017-12-29 18:27:33 +00:00
|
|
|
}
|
|
|
|
} else
|
2004-05-29 16:47:52 +00:00
|
|
|
#endif
|
2017-10-31 16:34:07 +00:00
|
|
|
#ifdef ENABLE_JUSTIFY
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(option, "punct") == 0) {
|
2020-10-21 09:21:11 +00:00
|
|
|
if (has_blank_char(argument))
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Non-blank characters required"));
|
2020-10-21 09:21:11 +00:00
|
|
|
else
|
2021-10-12 07:33:08 +00:00
|
|
|
punct = mallocstrcpy(punct, argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(option, "brackets") == 0) {
|
2020-10-21 09:21:11 +00:00
|
|
|
if (has_blank_char(argument))
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Non-blank characters required"));
|
2020-10-21 09:21:11 +00:00
|
|
|
else
|
2021-10-12 07:33:08 +00:00
|
|
|
brackets = mallocstrcpy(brackets, argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(option, "quotestr") == 0)
|
2021-10-12 07:33:08 +00:00
|
|
|
quotestr = mallocstrcpy(quotestr, argument);
|
2017-12-29 18:27:33 +00:00
|
|
|
else
|
2002-03-03 22:52:52 +00:00
|
|
|
#endif
|
2017-10-31 18:32:42 +00:00
|
|
|
#ifdef ENABLE_SPELLER
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(option, "speller") == 0)
|
2021-10-12 07:33:08 +00:00
|
|
|
alt_speller = mallocstrcpy(alt_speller, argument);
|
2017-12-29 18:27:33 +00:00
|
|
|
else
|
2005-03-10 20:55:11 +00:00
|
|
|
#endif
|
2020-10-03 09:21:18 +00:00
|
|
|
#ifndef NANO_TINY
|
2020-10-03 09:58:43 +00:00
|
|
|
if (strcmp(option, "backupdir") == 0)
|
2021-10-12 07:33:08 +00:00
|
|
|
backup_dir = mallocstrcpy(backup_dir, argument);
|
2020-10-03 09:58:43 +00:00
|
|
|
else if (strcmp(option, "wordchars") == 0)
|
2021-10-12 07:33:08 +00:00
|
|
|
word_chars = mallocstrcpy(word_chars, argument);
|
2020-10-03 09:58:43 +00:00
|
|
|
else if (strcmp(option, "guidestripe") == 0) {
|
|
|
|
if (!parse_num(argument, &stripe_column) || stripe_column <= 0) {
|
|
|
|
jot_error(N_("Guide column \"%s\" is invalid"), argument);
|
|
|
|
stripe_column = 0;
|
|
|
|
}
|
|
|
|
} else if (strcmp(option, "tabsize") == 0) {
|
2019-10-13 09:44:56 +00:00
|
|
|
if (!parse_num(argument, &tabsize) || tabsize <= 0) {
|
|
|
|
jot_error(N_("Requested tab size \"%s\" is invalid"), argument);
|
2017-12-29 18:27:33 +00:00
|
|
|
tabsize = -1;
|
|
|
|
}
|
2018-01-24 09:29:50 +00:00
|
|
|
}
|
2020-10-03 09:21:18 +00:00
|
|
|
#else
|
|
|
|
; /* Properly terminate any earlier 'else'. */
|
|
|
|
#endif
|
2017-12-29 18:27:33 +00:00
|
|
|
}
|
2005-03-10 20:55:11 +00:00
|
|
|
|
2019-06-15 17:34:23 +00:00
|
|
|
if (intros_only)
|
|
|
|
check_for_nonempty_syntax();
|
2016-02-28 20:38:14 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
fclose(rcstream);
|
2019-06-15 12:35:53 +00:00
|
|
|
free(buffer);
|
2017-12-29 18:27:33 +00:00
|
|
|
lineno = 0;
|
2004-07-30 22:52:44 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
return;
|
2001-04-18 04:28:54 +00:00
|
|
|
}
|
|
|
|
|
2016-11-27 17:21:04 +00:00
|
|
|
/* Read and interpret one of the two nanorc files. */
|
|
|
|
void parse_one_nanorc(void)
|
2001-04-18 04:28:54 +00:00
|
|
|
{
|
2019-06-16 15:50:35 +00:00
|
|
|
FILE *rcstream = fopen(nanorc, "rb");
|
2017-12-29 18:27:33 +00:00
|
|
|
|
|
|
|
/* If opening the file succeeded, parse it. Otherwise, only
|
|
|
|
* complain if the file actually exists. */
|
|
|
|
if (rcstream != NULL)
|
2019-06-13 10:20:38 +00:00
|
|
|
parse_rcfile(rcstream, FALSE, TRUE);
|
2017-12-29 18:27:33 +00:00
|
|
|
else if (errno != ENOENT)
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
|
2016-11-27 17:21:04 +00:00
|
|
|
}
|
|
|
|
|
2019-10-01 12:57:42 +00:00
|
|
|
bool have_nanorc(const char *path, const char *name)
|
2017-10-27 21:15:06 +00:00
|
|
|
{
|
2017-12-29 18:27:33 +00:00
|
|
|
if (path == NULL)
|
|
|
|
return FALSE;
|
2017-10-27 21:15:06 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
free(nanorc);
|
|
|
|
nanorc = concatenate(path, name);
|
2017-10-27 21:15:06 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
return is_good_file(nanorc);
|
2017-10-27 21:15:06 +00:00
|
|
|
}
|
|
|
|
|
2020-01-14 13:18:07 +00:00
|
|
|
/* Process the nanorc file that was specified on the command line (if any),
|
|
|
|
* and otherwise the system-wide rcfile followed by the user's rcfile. */
|
2016-11-27 17:21:04 +00:00
|
|
|
void do_rcfiles(void)
|
|
|
|
{
|
2020-01-14 11:41:22 +00:00
|
|
|
if (custom_nanorc) {
|
|
|
|
nanorc = get_full_path(custom_nanorc);
|
|
|
|
if (access(nanorc, F_OK) != 0)
|
|
|
|
die(_("Specified rcfile does not exist\n"));
|
|
|
|
} else
|
|
|
|
nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");
|
|
|
|
|
2019-06-16 15:50:35 +00:00
|
|
|
if (is_good_file(nanorc))
|
|
|
|
parse_one_nanorc();
|
2002-02-16 20:34:57 +00:00
|
|
|
|
2020-01-14 11:41:22 +00:00
|
|
|
if (custom_nanorc == NULL) {
|
2020-01-14 13:18:07 +00:00
|
|
|
const char *xdgconfdir = getenv("XDG_CONFIG_HOME");
|
|
|
|
|
|
|
|
get_homedir();
|
|
|
|
|
|
|
|
/* Now try to find a nanorc file in the user's home directory or in the
|
|
|
|
* XDG configuration directories, and process the first one found. */
|
|
|
|
if (have_nanorc(homedir, "/" HOME_RC_NAME) ||
|
|
|
|
have_nanorc(xdgconfdir, "/nano/" RCFILE_NAME) ||
|
|
|
|
have_nanorc(homedir, "/.config/nano/" RCFILE_NAME))
|
|
|
|
parse_one_nanorc();
|
|
|
|
else if (homedir == NULL && xdgconfdir == NULL)
|
|
|
|
jot_error(N_("I can't find my home directory! Wah!"));
|
2020-01-14 11:41:22 +00:00
|
|
|
}
|
2005-03-04 15:09:55 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
check_vitals_mapped();
|
2016-11-27 15:40:54 +00:00
|
|
|
|
2017-12-29 18:27:33 +00:00
|
|
|
free(nanorc);
|
2019-10-20 12:25:22 +00:00
|
|
|
nanorc = NULL;
|
2001-04-18 04:28:54 +00:00
|
|
|
}
|
|
|
|
|
2017-05-08 17:42:44 +00:00
|
|
|
#endif /* ENABLE_NANORC */
|