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
|
|
|
* *
|
2020-01-15 10:42:38 +00:00
|
|
|
* Copyright (C) 2001-2011, 2013-2020 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
|
|
|
* *
|
|
|
|
**************************************************************************/
|
|
|
|
|
2005-12-08 02:47:10 +00:00
|
|
|
#include "proto.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
|
2018-04-20 08:47:10 +00:00
|
|
|
#define HOME_RC_NAME ".nanorc"
|
2017-10-27 21:15:06 +00:00
|
|
|
#define RCFILE_NAME "nanorc"
|
2018-04-20 08:47:10 +00:00
|
|
|
#else
|
|
|
|
#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
|
2017-12-29 18:27:33 +00:00
|
|
|
{"constantshow", CONSTANT_SHOW},
|
2019-01-28 18:45:12 +00:00
|
|
|
{"emptyline", EMPTY_LINE},
|
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
|
2019-01-28 18:45:12 +00:00
|
|
|
{"jumpyscrolling", JUMPY_SCROLLING},
|
2018-05-13 07:47:40 +00:00
|
|
|
#ifdef ENABLE_LINENUMBERS
|
|
|
|
{"linenumbers", LINE_NUMBERS},
|
2013-01-01 03:24:39 +00:00
|
|
|
#endif
|
2019-03-10 16:05:19 +00:00
|
|
|
{"morespace", MORE_SPACE}, /* Deprecated; remove in 2021. */
|
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},
|
2019-10-13 14:17:04 +00:00
|
|
|
{"nopauses", NO_PAUSES}, /* Obsolete; remove in 2021. */
|
2017-10-29 20:00:09 +00:00
|
|
|
#ifdef ENABLE_WRAPPING
|
2019-03-10 16:05:19 +00:00
|
|
|
{"nowrap", NO_WRAP}, /* Deprecated; remove in 2021. */
|
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},
|
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. */
|
|
|
|
{"suspendable", SUSPENDABLE},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"tabsize", 0},
|
|
|
|
{"tempfile", TEMP_FILE},
|
|
|
|
{"view", VIEW_MODE},
|
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},
|
|
|
|
{"backup", BACKUP_FILE},
|
|
|
|
{"backupdir", 0},
|
|
|
|
{"casesensitive", CASE_SENSITIVE},
|
|
|
|
{"cutfromcursor", CUT_FROM_CURSOR},
|
2018-12-17 18:57:30 +00:00
|
|
|
{"guidestripe", 0},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"locking", LOCKING},
|
|
|
|
{"matchbrackets", 0},
|
|
|
|
{"noconvert", NO_CONVERT},
|
|
|
|
{"showcursor", SHOW_CURSOR},
|
|
|
|
{"smarthome", SMART_HOME},
|
2019-03-10 16:05:19 +00:00
|
|
|
{"smooth", SMOOTH_SCROLL}, /* Deprecated; remove in 2021. */
|
2017-12-29 18:27:33 +00:00
|
|
|
{"softwrap", SOFTWRAP},
|
|
|
|
{"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},
|
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},
|
2017-12-29 18:27:33 +00:00
|
|
|
{"selectedcolor", 0},
|
|
|
|
{"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
|
|
|
|
|
|
|
#define NUMBER_OF_MENUS 16
|
|
|
|
char *menunames[NUMBER_OF_MENUS] = { "main", "search", "replace", "replacewith",
|
|
|
|
"yesno", "gotoline", "writeout", "insert",
|
|
|
|
"extcmd", "help", "spell", "linter",
|
|
|
|
"browser", "whereisfile", "gotodir",
|
|
|
|
"all" };
|
|
|
|
int menusymbols[NUMBER_OF_MENUS] = { MMAIN, MWHEREIS, MREPLACE, MREPLACEWITH,
|
|
|
|
MYESNO, MGOTOLINE, MWRITEFILE, MINSERTFILE,
|
|
|
|
MEXTCMD, MHELP, MSPELL, MLINTER,
|
|
|
|
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"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_writeout_void;
|
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"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_insertfile_void;
|
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
|
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;
|
|
|
|
#ifdef ENABLE_SPELLER
|
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
|
|
|
|
#endif
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "curpos"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_cursorpos_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "gotoline"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_gotolinecolumn_void;
|
|
|
|
#ifdef ENABLE_JUSTIFY
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "justify"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_justify_void;
|
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;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "chopwordleft") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "cutwordleft")) /* Deprecated; remove in 2021. */
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = chop_previous_word;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "chopwordright") ||
|
2020-03-15 10:26:55 +00:00
|
|
|
!strcmp(input, "cutwordright")) /* Deprecated; remove in 2021. */
|
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"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_wordlinechar_count;
|
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;
|
new feature: bindable functions for toggling and jumping to "bookmarks"
With the 'bookmark' function, the user can place a bookmark on any
line in the buffer. Multiple lines can be bookmarked in this way.
With 'prevbookmark' and 'nextbookmark', the user can then easily
return to the bookmarked lines. The search for a bookmark wraps
around, as if start and end of buffer are connected.
[However, in this implementation, when a bookmarked line is deleted,
the bookmark is deleted too. This is undesirable. Also, when such
a deleted line is pasted elsewhere, the bookmark reappears with it,
and when pasted multiple times, the bookmark will be there as many
times. This is thoroughly undesirable. These behaviors will be
changed in a later commit.]
A bookmark is not yet visible in any way.
This fulfills https://savannah.gnu.org/bugs/?57577.
Requested-by: Ken Tyler <kent@werple.net.au>
Signed-off-by: Marco Diego Aurélio Mesquita <marcodiegomesquita@gmail.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
2018-11-12 20:30:47 +00:00
|
|
|
else if (!strcmp(input, "bookmark"))
|
|
|
|
s->func = bookmark;
|
|
|
|
else if (!strcmp(input, "prevbookmark"))
|
|
|
|
s->func = to_prev_bookmark;
|
|
|
|
else if (!strcmp(input, "nextbookmark"))
|
|
|
|
s->func = to_next_bookmark;
|
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;
|
|
|
|
#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"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = total_refresh;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "suspend"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = do_suspend_void;
|
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"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = get_history_older_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "newer"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = get_history_newer_void;
|
|
|
|
#endif
|
|
|
|
#ifndef NANO_TINY
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "dosformat"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = dos_format_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "macformat"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = mac_format_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "append"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = append_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "prepend"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = prepend_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "backup"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->func = backup_file_void;
|
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
|
|
|
|
s->func = do_toggle_void;
|
2019-12-13 18:03:38 +00:00
|
|
|
if (!strcmp(input, "nohelp"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = NO_HELP;
|
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"))
|
2019-12-13 17:54:53 +00:00
|
|
|
s->toggle = NO_COLOR_SYNTAX;
|
|
|
|
#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
|
2019-12-13 18:03:38 +00:00
|
|
|
else if (!strcmp(input, "nowrap"))
|
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
|
2020-03-15 10:17:46 +00:00
|
|
|
else if (!strcmp(input, "suspendable") ||
|
|
|
|
!strcmp(input, "suspendenable")) /* Deprecated; remove in 2022. */
|
2020-03-13 15:17:10 +00:00
|
|
|
s->toggle = SUSPENDABLE;
|
2019-12-13 17:54:53 +00:00
|
|
|
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);
|
|
|
|
char *message = charalloc(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);
|
2017-12-29 18:27:33 +00:00
|
|
|
}
|
2005-03-04 15:09:55 +00:00
|
|
|
|
2019-06-05 12:47:46 +00:00
|
|
|
if (packed == NULL || outcome != 0) {
|
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. */
|
|
|
|
live_syntax = (syntaxtype *)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;
|
|
|
|
* first handle three 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
|
2020-01-20 16:36:31 +00:00
|
|
|
else if (newsc->func == do_toggle_void)
|
2020-01-20 17:57:25 +00:00
|
|
|
menu &= MMAIN;
|
2016-09-01 07:36:47 +00:00
|
|
|
#endif
|
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
|
|
|
|
2018-12-30 18:28:17 +00:00
|
|
|
/* Disallow rebinding ^[ and frequent escape-sequence starter "Esc [". */
|
2020-01-22 12:12:52 +00:00
|
|
|
if (newsc->keycode == ESC_CODE || newsc->keycode == '[') {
|
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. */
|
|
|
|
if (newsc->func == do_toggle_void) {
|
2020-01-20 16:22:35 +00:00
|
|
|
for (keystruct *s = sclist; s != NULL; s = s->next)
|
2018-10-24 16:12:06 +00:00
|
|
|
if (s->func == do_toggle_void && s->toggle == newsc->toggle)
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2006-05-28 19:00:16 +00:00
|
|
|
/* Return the short value corresponding to the color named in colorname,
|
|
|
|
* and set bright to TRUE if that color is bright. */
|
2013-03-17 22:09:38 +00:00
|
|
|
short color_to_short(const char *colorname, bool *bright)
|
2006-05-28 19:00:16 +00:00
|
|
|
{
|
2020-01-31 15:11:38 +00:00
|
|
|
if (strncmp(colorname, "bright", 6) == 0) {
|
2017-12-29 18:27:33 +00:00
|
|
|
*bright = TRUE;
|
|
|
|
colorname += 6;
|
2018-01-15 12:15:23 +00:00
|
|
|
} else
|
|
|
|
*bright = FALSE;
|
2017-12-29 18:27:33 +00:00
|
|
|
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(colorname, "green") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
return COLOR_GREEN;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(colorname, "red") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
return COLOR_RED;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(colorname, "blue") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
return COLOR_BLUE;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(colorname, "white") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
return COLOR_WHITE;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(colorname, "yellow") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
return COLOR_YELLOW;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(colorname, "cyan") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
return COLOR_CYAN;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(colorname, "magenta") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
return COLOR_MAGENTA;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(colorname, "black") == 0)
|
2017-12-29 18:27:33 +00:00
|
|
|
return COLOR_BLACK;
|
2019-12-12 18:06:48 +00:00
|
|
|
else if (strcmp(colorname, "normal") == 0)
|
2018-04-01 07:49:58 +00:00
|
|
|
return USE_THE_DEFAULT;
|
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
|
|
|
{
|
|
|
|
char *comma = strchr(combostr, ',');
|
2018-08-24 00:50:16 +00:00
|
|
|
bool bright;
|
|
|
|
|
|
|
|
*attributes = A_NORMAL;
|
2018-03-30 08:25:39 +00:00
|
|
|
|
|
|
|
if (comma != NULL) {
|
2018-08-24 00:50:16 +00:00
|
|
|
*bg = color_to_short(comma + 1, &bright);
|
|
|
|
if (bright) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("A background color cannot be bright"));
|
2018-03-30 08:25:39 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2018-04-01 07:49:58 +00:00
|
|
|
if (*bg == BAD_COLOR)
|
2018-03-30 08:25:39 +00:00
|
|
|
return FALSE;
|
|
|
|
*comma = '\0';
|
|
|
|
} else
|
2018-04-01 07:49:58 +00:00
|
|
|
*bg = USE_THE_DEFAULT;
|
2018-03-30 08:25:39 +00:00
|
|
|
|
|
|
|
if (comma != combostr) {
|
2018-08-24 00:50:16 +00:00
|
|
|
*fg = color_to_short(combostr, &bright);
|
2018-04-01 07:49:58 +00:00
|
|
|
if (*fg == BAD_COLOR)
|
2018-03-30 08:25:39 +00:00
|
|
|
return FALSE;
|
2018-08-24 00:50:16 +00:00
|
|
|
|
|
|
|
if (bright)
|
|
|
|
*attributes = A_BOLD;
|
2018-03-30 08:25:39 +00:00
|
|
|
} else
|
2018-04-01 07:49:58 +00:00
|
|
|
*fg = USE_THE_DEFAULT;
|
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-03-04 15:08:34 +00:00
|
|
|
newcolor = (colortype *)nmalloc(sizeof(colortype));
|
|
|
|
|
|
|
|
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-03-03 10:27:37 +00:00
|
|
|
if (parse_combination(combostr, &trio->fg, &trio->bg, &trio->attributes)) {
|
2018-01-15 12:06:35 +00:00
|
|
|
free(combostr);
|
|
|
|
return trio;
|
|
|
|
} else {
|
|
|
|
free(combostr);
|
|
|
|
free(trio);
|
|
|
|
return NULL;
|
|
|
|
}
|
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') {
|
|
|
|
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. */
|
2019-06-05 11:00:35 +00:00
|
|
|
if (!compile(regexstring, NANO_REG_EXTENDED | REG_NOSUB, NULL))
|
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. */
|
|
|
|
newthing = (regexlisttype *)nmalloc(sizeof(regexlisttype));
|
2019-10-13 10:24:27 +00:00
|
|
|
newthing->full_regex = copy_of(regexstring);
|
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
|
|
|
|
|
|
|
/* Handle the four syntax-only commands. */
|
|
|
|
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
|
|
|
#ifdef ENABLE_COLOR
|
|
|
|
pick_up_name("tabgives", ptr, &live_syntax->tab);
|
2019-06-17 07:59:15 +00:00
|
|
|
#endif
|
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]) {
|
2019-04-03 15:34:05 +00:00
|
|
|
const keystruct *s = first_sc_for(inmenus[v], f->func);
|
2017-12-29 18:27:33 +00:00
|
|
|
if (!s) {
|
2018-08-06 17:31:46 +00:00
|
|
|
fprintf(stderr, _("No key is bound to function '%s' in "
|
2018-08-06 19:29:01 +00:00
|
|
|
"menu '%s'. Exiting.\n"), f->desc,
|
|
|
|
menu_to_name(inmenus[v]));
|
2017-12-29 18:27:33 +00:00
|
|
|
fprintf(stderr, _("If needed, use nano with the -I option "
|
|
|
|
"to adjust your nanorc settings.\n"));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
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);
|
2019-06-15 11:04:01 +00:00
|
|
|
if (strcasestr("icolor", keyword))
|
|
|
|
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
|
2019-10-13 10:24:27 +00:00
|
|
|
argument = copy_of(argument);
|
2019-09-30 17:41:06 +00:00
|
|
|
|
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);
|
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);
|
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)
|
2019-10-13 09:44:56 +00:00
|
|
|
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
|
|
|
}
|
2019-10-13 09:44:56 +00:00
|
|
|
free(argument);
|
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
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(option, "guidestripe") == 0) {
|
2019-10-13 09:44:56 +00:00
|
|
|
if (!parse_num(argument, &stripe_column) || stripe_column <= 0) {
|
|
|
|
jot_error(N_("Guide column \"%s\" is invalid"), argument);
|
2018-12-17 18:57:30 +00:00
|
|
|
stripe_column = 0;
|
|
|
|
}
|
2019-10-13 09:44:56 +00:00
|
|
|
free(argument);
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(option, "matchbrackets") == 0) {
|
2019-10-13 09:44:56 +00:00
|
|
|
if (has_blank_char(argument)) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Non-blank characters required"));
|
2019-10-13 09:44:56 +00:00
|
|
|
free(argument);
|
|
|
|
} else if (mbstrlen(argument) % 2 != 0) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Even number of characters required"));
|
2019-10-13 09:44:56 +00:00
|
|
|
free(argument);
|
2019-03-21 18:17:03 +00:00
|
|
|
} else
|
2019-10-13 09:44:56 +00:00
|
|
|
matchbrackets = argument;
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(option, "whitespace") == 0) {
|
2019-10-13 09:44:56 +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"));
|
2019-10-13 09:44:56 +00:00
|
|
|
free(argument);
|
2017-12-29 18:27:33 +00:00
|
|
|
} else {
|
2019-10-13 09:44:56 +00:00
|
|
|
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) {
|
2019-10-13 09:44:56 +00:00
|
|
|
if (has_blank_char(argument)) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Non-blank characters required"));
|
2019-10-13 09:44:56 +00:00
|
|
|
free(argument);
|
2018-05-24 18:43:08 +00:00
|
|
|
} else
|
2019-10-13 09:44:56 +00:00
|
|
|
punct = argument;
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(option, "brackets") == 0) {
|
2019-10-13 09:44:56 +00:00
|
|
|
if (has_blank_char(argument)) {
|
2019-06-15 12:07:57 +00:00
|
|
|
jot_error(N_("Non-blank characters required"));
|
2019-10-13 09:44:56 +00:00
|
|
|
free(argument);
|
2018-05-24 18:43:08 +00:00
|
|
|
} else
|
2019-10-13 09:44:56 +00:00
|
|
|
brackets = argument;
|
2019-12-12 18:06:48 +00:00
|
|
|
} else if (strcmp(option, "quotestr") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
quotestr = argument;
|
2017-12-29 18:27:33 +00:00
|
|
|
else
|
2002-03-03 22:52:52 +00:00
|
|
|
#endif
|
2005-11-15 03:17:35 +00:00
|
|
|
#ifndef NANO_TINY
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(option, "backupdir") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
backup_dir = argument;
|
2017-12-29 18:27:33 +00:00
|
|
|
else
|
2019-12-12 18:06:48 +00:00
|
|
|
if (strcmp(option, "wordchars") == 0)
|
2019-10-13 09:44:56 +00:00
|
|
|
word_chars = argument;
|
2017-12-29 18:27:33 +00:00
|
|
|
else
|
2004-02-28 16:24:31 +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)
|
2019-10-13 09:44:56 +00:00
|
|
|
alt_speller = argument;
|
2017-12-29 18:27:33 +00:00
|
|
|
else
|
2005-03-10 20:55:11 +00:00
|
|
|
#endif
|
2019-12-12 18:06:48 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-10-13 09:44:56 +00:00
|
|
|
free(argument);
|
2018-01-24 09:29:50 +00:00
|
|
|
}
|
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 */
|