blob: a63e13bfc106382facffaae1940b545f125fb12b [file] [log] [blame]
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001/**************************************************************************
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02002 * rcfile.c -- This file is part of GNU nano. *
Chris Allegretta8d8e0122001-04-18 04:28:54 +00003 * *
Benno Schulenberg7a9f4a42014-04-30 20:18:26 +00004 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, *
5 * 2010, 2011, 2013, 2014 Free Software Foundation, Inc. *
Benno Schulenberg406e5242016-08-29 15:14:18 +02006 * Copyright (C) 2014 Mike Frysinger *
7 * Copyright (C) 2014, 2015, 2016 Benno Schulenberg *
8 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02009 * GNU nano is free software: you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published *
11 * by the Free Software Foundation, either version 3 of the License, *
12 * or (at your option) any later version. *
Chris Allegretta8d8e0122001-04-18 04:28:54 +000013 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020014 * GNU nano is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty *
16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
17 * See the GNU General Public License for more details. *
Chris Allegretta8d8e0122001-04-18 04:28:54 +000018 * *
19 * You should have received a copy of the GNU General Public License *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020020 * along with this program. If not, see http://www.gnu.org/licenses/. *
Chris Allegretta8d8e0122001-04-18 04:28:54 +000021 * *
22 **************************************************************************/
23
David Lawrence Ramsey034b9942005-12-08 02:47:10 +000024#include "proto.h"
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000025
Benno Schulenberg38142832014-03-30 20:37:40 +000026#include <glob.h>
Chris Allegretta34f80982002-01-22 20:09:20 +000027#include <stdarg.h>
Chris Allegretta8d8e0122001-04-18 04:28:54 +000028#include <string.h>
29#include <stdio.h>
30#include <errno.h>
Chris Allegretta4dc03d52002-05-11 03:04:44 +000031#include <unistd.h>
David Lawrence Ramsey9830d752004-05-13 17:19:54 +000032#include <ctype.h>
Chris Allegretta8d8e0122001-04-18 04:28:54 +000033
Benno Schulenbergeea09082014-04-13 20:50:20 +000034#ifndef DISABLE_NANORC
Chris Allegretta8d8e0122001-04-18 04:28:54 +000035
Benno Schulenberg77023a72016-11-27 16:34:34 +010036#ifndef RCFILE_NAME
37#define RCFILE_NAME ".nanorc"
38#endif
39
David Lawrence Ramsey68351022006-08-21 21:37:39 +000040static const rcoption rcopts[] = {
David Lawrence Ramsey4d72de72006-04-12 15:27:40 +000041 {"boldtext", BOLD_TEXT},
Faissal Bensefiade95ca62016-10-20 09:44:29 +010042#ifdef ENABLE_LINENUMBERS
43 {"linenumbers", LINE_NUMBERS},
44#endif
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +000045#ifndef DISABLE_JUSTIFY
46 {"brackets", 0},
47#endif
Benno Schulenberg79526152015-07-15 19:40:37 +000048 {"const", CONST_UPDATE}, /* deprecated form, remove in 2018 */
49 {"constantshow", CONST_UPDATE},
Chris Allegretta6df90f52002-07-19 01:08:59 +000050#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6c1e6612002-01-19 16:52:34 +000051 {"fill", 0},
Chris Allegretta6df90f52002-07-19 01:08:59 +000052#endif
Benno Schulenberg7c2f53b2015-06-18 18:51:27 +000053#ifndef DISABLE_HISTORIES
54 {"historylog", HISTORYLOG},
Chris Allegrettabf88d272013-01-01 03:24:39 +000055#endif
Benno Schulenberg7c2f53b2015-06-18 18:51:27 +000056 {"morespace", MORE_SPACE},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +000057#ifndef DISABLE_MOUSE
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000058 {"mouse", USE_MOUSE},
59#endif
Benno Schulenberg0636d7b2014-04-03 20:23:07 +000060#ifndef DISABLE_MULTIBUFFER
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000061 {"multibuffer", MULTIBUFFER},
62#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000063 {"nohelp", NO_HELP},
David Lawrence Ramseya0168ca2005-11-05 17:35:44 +000064 {"nonewlines", NO_NEWLINES},
Chris Allegretta6df90f52002-07-19 01:08:59 +000065#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000066 {"nowrap", NO_WRAP},
Chris Allegretta6df90f52002-07-19 01:08:59 +000067#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000068#ifndef DISABLE_OPERATINGDIR
69 {"operatingdir", 0},
70#endif
Benno Schulenberg7c2f53b2015-06-18 18:51:27 +000071#ifndef DISABLE_HISTORIES
Benno Schulenbergcadb4f32015-07-15 19:50:55 +000072 {"poslog", POS_HISTORY}, /* deprecated form, remove in 2018 */
73 {"positionlog", POS_HISTORY},
Benno Schulenberg7c2f53b2015-06-18 18:51:27 +000074#endif
Chris Allegretta7662c862003-01-13 01:35:15 +000075 {"preserve", PRESERVE},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +000076#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +000077 {"punct", 0},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000078 {"quotestr", 0},
79#endif
David Lawrence Ramseyf38230a2004-04-21 22:25:16 +000080 {"rebinddelete", REBIND_DELETE},
David Lawrence Ramsey057edf72005-08-10 21:22:15 +000081 {"rebindkeypad", REBIND_KEYPAD},
David Lawrence Ramseyf3ecffd2005-06-16 18:48:30 +000082#ifdef HAVE_REGEX_H
83 {"regexp", USE_REGEXP},
84#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000085#ifndef DISABLE_SPELLER
Chris Allegretta6c1e6612002-01-19 16:52:34 +000086 {"speller", 0},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000087#endif
88 {"suspend", SUSPEND},
89 {"tabsize", 0},
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +000090 {"tempfile", TEMP_FILE},
Chris Allegretta6c1e6612002-01-19 16:52:34 +000091 {"view", VIEW_MODE},
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000092#ifndef NANO_TINY
Benno Schulenberg7c2f53b2015-06-18 18:51:27 +000093 {"allow_insecure_backup", INSECURE_BACKUP},
David Lawrence Ramsey63990002005-06-17 19:01:00 +000094 {"autoindent", AUTOINDENT},
95 {"backup", BACKUP_FILE},
96 {"backupdir", 0},
97 {"backwards", BACKWARDS_SEARCH},
98 {"casesensitive", CASE_SENSITIVE},
99 {"cut", CUT_TO_END},
Chris Allegretta9f983332016-02-25 21:04:45 +0000100 {"justifytrim", JUSTIFY_TRIM},
Benno Schulenberg7c2f53b2015-06-18 18:51:27 +0000101 {"locking", LOCKING},
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +0000102 {"matchbrackets", 0},
David Lawrence Ramsey63990002005-06-17 19:01:00 +0000103 {"noconvert", NO_CONVERT},
David Lawrence Ramseye29111f2005-06-17 19:06:25 +0000104 {"quickblank", QUICK_BLANK},
Benno Schulenberg7c2f53b2015-06-18 18:51:27 +0000105 {"quiet", QUIET},
Benno Schulenbergb92d35d2016-09-11 09:41:09 +0200106 {"showcursor", SHOW_CURSOR},
David Lawrence Ramsey63990002005-06-17 19:01:00 +0000107 {"smarthome", SMART_HOME},
108 {"smooth", SMOOTH_SCROLL},
Benno Schulenberg44995202015-06-20 18:48:43 +0000109 {"softwrap", SOFTWRAP},
David Lawrence Ramsey63990002005-06-17 19:01:00 +0000110 {"tabstospaces", TABS_TO_SPACES},
Benno Schulenbergeac04462015-08-09 16:31:01 +0000111 {"unix", MAKE_IT_UNIX},
David Lawrence Ramsey483ea322004-05-29 16:25:30 +0000112 {"whitespace", 0},
David Lawrence Ramsey4f03daf2005-08-10 22:12:28 +0000113 {"wordbounds", WORD_BOUNDS},
Benno Schulenberg6f129922016-06-30 18:02:45 +0200114 {"wordchars", 0},
David Lawrence Ramsey483ea322004-05-29 16:25:30 +0000115#endif
Benno Schulenberg16639942014-05-03 18:24:45 +0000116#ifndef DISABLE_COLOR
117 {"titlecolor", 0},
Benno Schulenbergde2aa4f2016-10-20 10:07:48 +0200118 {"numbercolor", 0},
Benno Schulenberg16639942014-05-03 18:24:45 +0000119 {"statuscolor", 0},
120 {"keycolor", 0},
121 {"functioncolor", 0},
122#endif
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +0000123 {NULL, 0}
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000124};
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000125
David Lawrence Ramseya6d26d02004-07-30 22:52:44 +0000126static bool errors = FALSE;
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000127 /* Whether we got any errors while parsing an rcfile. */
David Lawrence Ramsey2cf6d712005-06-28 06:25:34 +0000128static size_t lineno = 0;
David Lawrence Ramsey6335fb52007-01-01 05:15:32 +0000129 /* If we did, the line number where the last error occurred. */
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000130static char *nanorc = NULL;
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000131 /* The path to the rcfile we're parsing. */
Benno Schulenberg00389922014-04-04 11:59:03 +0000132#ifndef DISABLE_COLOR
Benno Schulenberg275e9f02016-02-28 20:38:14 +0000133static bool opensyntax = FALSE;
134 /* Whether we're allowed to add to the last syntax. When a file ends,
135 * or when a new syntax command is seen, this bool becomes FALSE. */
Benno Schulenberg8a5ae212016-03-10 20:36:12 +0000136static syntaxtype *live_syntax;
Benno Schulenberg04262f02016-03-10 20:06:01 +0000137 /* The syntax that is currently being parsed. */
Benno Schulenberg8fbb9222016-03-13 20:05:36 +0000138static colortype *lastcolor = NULL;
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000139 /* The end of the color list for the current syntax. */
140#endif
Chris Allegrettaf478f832002-01-18 21:54:35 +0000141
David Lawrence Ramsey68351022006-08-21 21:37:39 +0000142/* We have an error in some part of the rcfile. Print the error message
143 * on stderr, and then make the user hit Enter to continue starting
144 * nano. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000145void rcfile_error(const char *msg, ...)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000146{
147 va_list ap;
148
Chris Allegrettaa30eb782009-02-09 04:03:20 +0000149 if (ISSET(QUIET))
150 return;
151
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000152 fprintf(stderr, "\n");
David Lawrence Ramseya6d26d02004-07-30 22:52:44 +0000153 if (lineno > 0) {
154 errors = TRUE;
David Lawrence Ramseye796a7b2005-08-01 05:54:11 +0000155 fprintf(stderr, _("Error in %s on line %lu: "), nanorc, (unsigned long)lineno);
David Lawrence Ramseya6d26d02004-07-30 22:52:44 +0000156 }
Chris Allegretta78f0fc62002-03-29 19:41:57 +0000157
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000158 va_start(ap, msg);
David Lawrence Ramsey576bf332004-07-12 03:10:30 +0000159 vfprintf(stderr, _(msg), ap);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000160 va_end(ap);
David Lawrence Ramsey6420d442004-08-11 05:13:08 +0000161
162 fprintf(stderr, "\n");
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000163}
Benno Schulenbergb341f292014-06-19 20:05:24 +0000164#endif /* !DISABLE_NANORC */
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000165
Benno Schulenbergb341f292014-06-19 20:05:24 +0000166#if !defined(DISABLE_NANORC) || !defined(DISABLE_HISTORIES)
David Lawrence Ramsey68351022006-08-21 21:37:39 +0000167/* Parse the next word from the string, null-terminate it, and return
168 * a pointer to the first character after the null terminator. The
169 * returned pointer will point to '\0' if we hit the end of the line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000170char *parse_next_word(char *ptr)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000171{
David Lawrence Ramseyd8640482005-06-12 17:48:46 +0000172 while (!isblank(*ptr) && *ptr != '\0')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000173 ptr++;
174
Chris Allegretta13fd44b2002-01-02 13:59:11 +0000175 if (*ptr == '\0')
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000176 return ptr;
Chris Allegrettaf478f832002-01-18 21:54:35 +0000177
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000178 /* Null-terminate and advance ptr. */
179 *ptr++ = '\0';
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000180
David Lawrence Ramseyd8640482005-06-12 17:48:46 +0000181 while (isblank(*ptr))
Chris Allegretta08893e02001-11-29 02:42:27 +0000182 ptr++;
183
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000184 return ptr;
185}
Benno Schulenbergb341f292014-06-19 20:05:24 +0000186#endif /* !DISABLE_NANORC || !DISABLE_HISTORIES */
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000187
Benno Schulenbergb341f292014-06-19 20:05:24 +0000188#ifndef DISABLE_NANORC
David Lawrence Ramseyd89617f2006-01-06 21:51:10 +0000189/* Parse an argument, with optional quotes, after a keyword that takes
190 * one. If the next word starts with a ", we say that it ends with the
191 * last " of the line. Otherwise, we interpret it as usual, so that the
192 * arguments can contain "'s too. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000193char *parse_argument(char *ptr)
194{
David Lawrence Ramsey5cbd9902006-04-05 21:28:52 +0000195 const char *ptr_save = ptr;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000196 char *last_quote = NULL;
197
198 assert(ptr != NULL);
199
200 if (*ptr != '"')
201 return parse_next_word(ptr);
202
203 do {
204 ptr++;
205 if (*ptr == '"')
206 last_quote = ptr;
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000207 } while (*ptr != '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +0000208
209 if (last_quote == NULL) {
210 if (*ptr == '\0')
211 ptr = NULL;
212 else
213 *ptr++ = '\0';
David Lawrence Ramsey4bb60db2006-06-08 02:50:56 +0000214 rcfile_error(N_("Argument '%s' has an unterminated \""), ptr_save);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000215 } else {
216 *last_quote = '\0';
217 ptr = last_quote + 1;
218 }
219 if (ptr != NULL)
David Lawrence Ramseyd8640482005-06-12 17:48:46 +0000220 while (isblank(*ptr))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000221 ptr++;
222 return ptr;
223}
224
Benno Schulenberg00389922014-04-04 11:59:03 +0000225#ifndef DISABLE_COLOR
Benno Schulenbergb8aae4d2016-03-11 16:39:27 +0000226/* Pass over the current regex string in the line starting at ptr,
227 * null-terminate it, and return a pointer to the /next/ word. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000228char *parse_next_regex(char *ptr)
229{
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000230 assert(ptr != NULL);
231
Benno Schulenbergb8aae4d2016-03-11 16:39:27 +0000232 /* Continue until the end of line, or until a " followed by a
233 * blank character or the end of line. */
234 while (*ptr != '\0' && (*ptr != '"' ||
235 (*(ptr + 1) != '\0' && !isblank(*(ptr + 1)))))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000236 ptr++;
237
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000238 assert(*ptr == '"' || *ptr == '\0');
239
240 if (*ptr == '\0') {
David Lawrence Ramsey08c70ae2005-03-14 17:47:17 +0000241 rcfile_error(
242 N_("Regex strings must begin and end with a \" character"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000243 return NULL;
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000244 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000245
David Lawrence Ramseye54f1c42006-10-29 21:14:53 +0000246 /* Null-terminate and advance ptr. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000247 *ptr++ = '\0';
248
David Lawrence Ramseyd8640482005-06-12 17:48:46 +0000249 while (isblank(*ptr))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000250 ptr++;
251
252 return ptr;
253}
254
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000255/* Compile the regular expression regex to see if it's valid. Return
Benno Schulenbergb8aae4d2016-03-11 16:39:27 +0000256 * TRUE if it is, and FALSE otherwise. */
Benno Schulenberg6ed64622016-03-13 19:37:21 +0000257bool nregcomp(const char *regex, int compile_flags)
Chris Allegrettace452fb2003-02-03 02:56:44 +0000258{
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000259 regex_t preg;
Chris Allegretta6b83e522008-08-30 05:16:20 +0000260 const char *r = fixbounds(regex);
Benno Schulenberg6ed64622016-03-13 19:37:21 +0000261 int rc = regcomp(&preg, r, compile_flags);
Chris Allegrettace452fb2003-02-03 02:56:44 +0000262
263 if (rc != 0) {
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000264 size_t len = regerror(rc, &preg, NULL, 0);
Chris Allegrettace452fb2003-02-03 02:56:44 +0000265 char *str = charalloc(len);
266
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000267 regerror(rc, &preg, str, len);
Chris Allegretta6b83e522008-08-30 05:16:20 +0000268 rcfile_error(N_("Bad regex \"%s\": %s"), r, str);
Chris Allegrettace452fb2003-02-03 02:56:44 +0000269 free(str);
270 }
David Lawrence Ramsey9adace82005-03-04 15:09:55 +0000271
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000272 regfree(&preg);
David Lawrence Ramseydb958022005-07-13 20:18:46 +0000273 return (rc == 0);
Chris Allegrettace452fb2003-02-03 02:56:44 +0000274}
275
Benno Schulenbergb8aae4d2016-03-11 16:39:27 +0000276/* Parse the next syntax name and its possible extension regexes from the
277 * line at ptr, and add it to the global linked list of color syntaxes. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000278void parse_syntax(char *ptr)
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000279{
Benno Schulenberg2f63e8d2016-03-09 21:00:42 +0000280 char *nameptr;
281 /* A pointer to what should be the name of the syntax. */
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000282
Benno Schulenberg275e9f02016-02-28 20:38:14 +0000283 opensyntax = FALSE;
284
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000285 assert(ptr != NULL);
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000286
Benno Schulenbergb0bdfbb2016-03-09 20:28:50 +0000287 /* Check that the syntax name is not empty. */
288 if (*ptr == '\0' || (*ptr == '"' &&
289 (*(ptr + 1) == '\0' || *(ptr + 1) == '"'))) {
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000290 rcfile_error(N_("Missing syntax name"));
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000291 return;
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000292 }
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000293
Benno Schulenbergb0bdfbb2016-03-09 20:28:50 +0000294 nameptr = ++ptr;
295 ptr = parse_next_word(ptr);
296
297 /* Check that the name starts and ends with a double quote. */
298 if (*(nameptr - 1) != '\x22' || nameptr[strlen(nameptr) - 1] != '\x22') {
299 rcfile_error(N_("A syntax name must be quoted"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000300 return;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000301 }
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000302
Benno Schulenbergb0bdfbb2016-03-09 20:28:50 +0000303 /* Strip the end quote. */
304 nameptr[strlen(nameptr) - 1] = '\0';
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000305
Benno Schulenberg717e6972016-02-29 10:29:52 +0000306 /* Redefining the "none" syntax is not allowed. */
307 if (strcmp(nameptr, "none") == 0) {
308 rcfile_error(N_("The \"none\" syntax is reserved"));
309 return;
310 }
311
Benno Schulenberg04262f02016-03-10 20:06:01 +0000312 /* Initialize a new syntax struct. */
Benno Schulenberg8a5ae212016-03-10 20:36:12 +0000313 live_syntax = (syntaxtype *)nmalloc(sizeof(syntaxtype));
314 live_syntax->name = mallocstrcpy(NULL, nameptr);
315 live_syntax->extensions = NULL;
316 live_syntax->headers = NULL;
317 live_syntax->magics = NULL;
318 live_syntax->linter = NULL;
319 live_syntax->formatter = NULL;
Mike Scalora6a2032f2016-05-25 22:13:50 +0200320 live_syntax->comment = NULL;
Benno Schulenberg8a5ae212016-03-10 20:36:12 +0000321 live_syntax->color = NULL;
Benno Schulenberg8fbb9222016-03-13 20:05:36 +0000322 lastcolor = NULL;
Benno Schulenberg8a5ae212016-03-10 20:36:12 +0000323 live_syntax->nmultis = 0;
Benno Schulenberg04262f02016-03-10 20:06:01 +0000324
325 /* Hook the new syntax in at the top of the list. */
Benno Schulenberg8a5ae212016-03-10 20:36:12 +0000326 live_syntax->next = syntaxes;
327 syntaxes = live_syntax;
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000328
Benno Schulenberg275e9f02016-02-28 20:38:14 +0000329 opensyntax = TRUE;
330
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000331#ifdef DEBUG
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000332 fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr);
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000333#endif
334
David Lawrence Ramsey179b1ba2005-08-01 04:23:29 +0000335 /* The default syntax should have no associated extensions. */
Benno Schulenberg8a5ae212016-03-10 20:36:12 +0000336 if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
David Lawrence Ramseyd152ad32005-08-01 04:59:34 +0000337 rcfile_error(
Benno Schulenberg2994ea92016-03-10 09:46:21 +0000338 N_("The \"default\" syntax does not accept extensions"));
David Lawrence Ramsey179b1ba2005-08-01 04:23:29 +0000339 return;
340 }
341
Benno Schulenberg2f63e8d2016-03-09 21:00:42 +0000342 /* If there seem to be extension regexes, pick them up. */
343 if (*ptr != '\0')
Benno Schulenberg8a5ae212016-03-10 20:36:12 +0000344 grab_and_store("extension", ptr, &live_syntax->extensions);
Chris Allegrettab00d0b92011-02-13 04:23:10 +0000345}
Benno Schulenberg00389922014-04-04 11:59:03 +0000346#endif /* !DISABLE_COLOR */
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000347
Benno Schulenberg4651f492014-06-27 16:14:52 +0000348/* Check whether the given executable function is "universal" (meaning
349 * any horizontal movement or deletion) and thus is present in almost
350 * all menus. */
351bool is_universal(void (*func))
352{
353 if (func == do_left || func == do_right ||
354 func == do_home || func == do_end ||
355 func == do_prev_word_void || func == do_next_word_void ||
356 func == do_verbatim_input || func == do_cut_text_void ||
357 func == do_delete || func == do_backspace ||
358 func == do_tab || func == do_enter)
359 return TRUE;
360 else
361 return FALSE;
362}
363
Benno Schulenbergf7c5eee2014-04-08 11:43:50 +0000364/* Bind or unbind a key combo, to or from a function. */
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000365void parse_binding(char *ptr, bool dobind)
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000366{
367 char *keyptr = NULL, *keycopy = NULL, *funcptr = NULL, *menuptr = NULL;
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000368 sc *s, *newsc = NULL;
Benno Schulenbergf7c5eee2014-04-08 11:43:50 +0000369 int menu;
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000370
371 assert(ptr != NULL);
372
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000373#ifdef DEBUG
374 fprintf(stderr, "Starting the rebinding code...\n");
375#endif
376
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000377 if (*ptr == '\0') {
378 rcfile_error(N_("Missing key name"));
379 return;
380 }
381
382 keyptr = ptr;
383 ptr = parse_next_word(ptr);
384 keycopy = mallocstrcpy(NULL, keyptr);
Benno Schulenbergf7c5eee2014-04-08 11:43:50 +0000385
386 if (strlen(keycopy) < 2) {
387 rcfile_error(N_("Key name is too short"));
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000388 goto free_copy;
Benno Schulenbergf7c5eee2014-04-08 11:43:50 +0000389 }
390
391 /* Uppercase only the first two or three characters of the key name. */
392 keycopy[0] = toupper(keycopy[0]);
393 keycopy[1] = toupper(keycopy[1]);
394 if (keycopy[0] == 'M' && keycopy[1] == '-') {
395 if (strlen(keycopy) > 2)
396 keycopy[2] = toupper(keycopy[2]);
397 else {
398 rcfile_error(N_("Key name is too short"));
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000399 goto free_copy;
Benno Schulenbergf7c5eee2014-04-08 11:43:50 +0000400 }
401 }
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000402
Benno Schulenberg94b1d012014-04-21 18:05:11 +0000403 /* Allow the codes for Insert and Delete to be rebound, but apart
404 * from those two only Control, Meta and Function sequences. */
405 if (!strcasecmp(keycopy, "Ins") || !strcasecmp(keycopy, "Del"))
406 keycopy[1] = tolower(keycopy[1]);
407 else if (keycopy[0] != '^' && keycopy[0] != 'M' && keycopy[0] != 'F') {
Benno Schulenbergf7c5eee2014-04-08 11:43:50 +0000408 rcfile_error(N_("Key name must begin with \"^\", \"M\", or \"F\""));
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000409 goto free_copy;
Rishabh Davee2027ae2016-09-14 17:19:53 +0530410 } else if ((keycopy[0] == 'M' && keycopy[1] != '-') ||
Rishabh Dave01bf0342016-10-11 19:02:02 +0530411 (keycopy[0] == '^' && ((keycopy[1] < 'A' || keycopy[1] > 'z') ||
412 keycopy[1] == '[' || keycopy[1] == '`' ||
Rishabh Davee2027ae2016-09-14 17:19:53 +0530413 (strlen(keycopy) > 2 && strcmp(keycopy, "^Space") != 0))) ||
414 (strlen(keycopy) > 3 && strcmp(keycopy, "^Space") != 0 &&
415 strcmp(keycopy, "M-Space") != 0)) {
Benno Schulenberg14d1b3b2016-02-10 15:06:45 +0000416 rcfile_error(N_("Key name %s is invalid"), keycopy);
417 goto free_copy;
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000418 }
419
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000420 if (dobind) {
421 funcptr = ptr;
422 ptr = parse_next_word(ptr);
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000423
Benno Schulenberged0086b2014-06-09 14:33:00 +0000424 if (funcptr[0] == '\0') {
Benno Schulenberge15abc92014-04-21 18:12:29 +0000425 rcfile_error(N_("Must specify a function to bind the key to"));
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000426 goto free_copy;
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000427 }
428 }
Chris Allegrettae9dee882009-11-21 16:26:59 +0000429
430 menuptr = ptr;
431 ptr = parse_next_word(ptr);
432
Benno Schulenberged0086b2014-06-09 14:33:00 +0000433 if (menuptr[0] == '\0') {
Benno Schulenbergd19be5a2014-04-08 18:38:45 +0000434 /* TRANSLATORS: Do not translate the word "all". */
Benno Schulenberge15abc92014-04-21 18:12:29 +0000435 rcfile_error(N_("Must specify a menu (or \"all\") in which to bind/unbind the key"));
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000436 goto free_copy;
Benno Schulenbergf7c5eee2014-04-08 11:43:50 +0000437 }
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000438
439 if (dobind) {
Benno Schulenberg1f934e32014-04-13 11:56:08 +0000440 newsc = strtosc(funcptr);
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000441 if (newsc == NULL) {
Benno Schulenbergf7c5eee2014-04-08 11:43:50 +0000442 rcfile_error(N_("Cannot map name \"%s\" to a function"), funcptr);
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000443 goto free_copy;
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000444 }
445 }
446
Benno Schulenberge15abc92014-04-21 18:12:29 +0000447 menu = strtomenu(menuptr);
448 if (menu < 1) {
449 rcfile_error(N_("Cannot map name \"%s\" to a menu"), menuptr);
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000450 goto free_copy;
Benno Schulenberge15abc92014-04-21 18:12:29 +0000451 }
452
Chris Allegrettae9dee882009-11-21 16:26:59 +0000453#ifdef DEBUG
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000454 if (dobind)
Benno Schulenberg27a52a82014-04-21 13:07:18 +0000455 fprintf(stderr, "newsc address is now %ld, assigned func = %ld, menu = %x\n",
456 (long)&newsc, (long)newsc->scfunc, menu);
Benno Schulenberg111071a2014-05-13 08:34:29 +0000457 else
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000458 fprintf(stderr, "unbinding \"%s\" from menu %x\n", keycopy, menu);
Chris Allegrettae9dee882009-11-21 16:26:59 +0000459#endif
460
Benno Schulenberg79ff3932015-03-08 15:42:52 +0000461 if (dobind) {
Benno Schulenberg4651f492014-06-27 16:14:52 +0000462 subnfunc *f;
463 int mask = 0;
464
465 /* Tally up the menus where the function exists. */
466 for (f = allfuncs; f != NULL; f = f->next)
467 if (f->scfunc == newsc->scfunc)
468 mask = mask | f->menus;
469
Benno Schulenberg7b7d2bf2016-09-01 09:36:47 +0200470#ifndef NANO_TINY
Benno Schulenberg79ff3932015-03-08 15:42:52 +0000471 /* Handle the special case of the toggles. */
472 if (newsc->scfunc == do_toggle_void)
473 mask = MMAIN;
Benno Schulenberg7b7d2bf2016-09-01 09:36:47 +0200474#endif
Benno Schulenberg79ff3932015-03-08 15:42:52 +0000475
Benno Schulenberg4651f492014-06-27 16:14:52 +0000476 /* Now limit the given menu to those where the function exists. */
477 if (is_universal(newsc->scfunc))
478 menu = menu & MMOST;
479 else
480 menu = menu & mask;
481
482 if (!menu) {
483 rcfile_error(N_("Function '%s' does not exist in menu '%s'"), funcptr, menuptr);
484 free(newsc);
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000485 goto free_copy;
Benno Schulenberg4651f492014-06-27 16:14:52 +0000486 }
487
Benno Schulenberg1f866c22015-07-15 20:13:05 +0000488 newsc->menus = menu;
Benno Schulenberg55878ef2016-10-15 17:55:19 +0200489 assign_keyinfo(newsc, keycopy, 0);
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000490
Benno Schulenberge2950702016-07-23 14:42:40 +0200491 /* Do not allow rebinding a frequent escape-sequence starter: Esc [. */
Benno Schulenberg1c9ab8b2016-07-24 21:49:07 +0200492 if (newsc->meta && newsc->keycode == 91) {
Benno Schulenberg111071a2014-05-13 08:34:29 +0000493 rcfile_error(N_("Sorry, keystroke \"%s\" may not be rebound"), newsc->keystr);
494 free(newsc);
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000495 goto free_copy;
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000496 }
Benno Schulenberg63370952016-01-14 14:44:11 +0000497#ifdef DEBUG
498 fprintf(stderr, "s->keystr = \"%s\"\n", newsc->keystr);
Benno Schulenberg1c9ab8b2016-07-24 21:49:07 +0200499 fprintf(stderr, "s->keycode = \"%d\"\n", newsc->keycode);
Benno Schulenberg63370952016-01-14 14:44:11 +0000500#endif
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000501 }
502
503 /* Now find and delete any existing same shortcut in the menu(s). */
Chris Allegrettae9dee882009-11-21 16:26:59 +0000504 for (s = sclist; s != NULL; s = s->next) {
Benno Schulenberg1f866c22015-07-15 20:13:05 +0000505 if ((s->menus & menu) && !strcmp(s->keystr, keycopy)) {
Chris Allegrettae9dee882009-11-21 16:26:59 +0000506#ifdef DEBUG
Benno Schulenberg1f866c22015-07-15 20:13:05 +0000507 fprintf(stderr, "deleting entry from among menus %x\n", s->menus);
Chris Allegrettae9dee882009-11-21 16:26:59 +0000508#endif
Benno Schulenberg1f866c22015-07-15 20:13:05 +0000509 s->menus &= ~menu;
Chris Allegrettae9dee882009-11-21 16:26:59 +0000510 }
511 }
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000512
513 if (dobind) {
Benno Schulenberg7b7d2bf2016-09-01 09:36:47 +0200514#ifndef NANO_TINY
Benno Schulenberg5ac6a872015-07-06 17:51:17 +0000515 /* If this is a toggle, copy its sequence number. */
516 if (newsc->scfunc == do_toggle_void) {
517 for (s = sclist; s != NULL; s = s->next)
Benno Schulenberg3d2784e2015-08-03 08:03:22 +0000518 if (s->scfunc == do_toggle_void && s->toggle == newsc->toggle)
Benno Schulenberg5ac6a872015-07-06 17:51:17 +0000519 newsc->ordinal = s->ordinal;
520 } else
521 newsc->ordinal = 0;
Benno Schulenberg7b7d2bf2016-09-01 09:36:47 +0200522#endif
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +0000523 /* Add the new shortcut at the start of the list. */
524 newsc->next = sclist;
525 sclist = newsc;
Benno Schulenberg95e1f552015-08-03 19:52:48 +0000526 return;
527 }
528
529 free_copy:
530 free(keycopy);
Chris Allegrettae9dee882009-11-21 16:26:59 +0000531}
532
Benno Schulenberg981a1d32016-11-27 17:27:04 +0100533/* Verify that the given file is not a folder nor a device. */
534bool is_good_file(char *file)
535{
536 struct stat rcinfo;
537
538 /* If the thing exists, it may not be a directory nor a device. */
539 if (stat(file, &rcinfo) != -1 && (S_ISDIR(rcinfo.st_mode) ||
540 S_ISCHR(rcinfo.st_mode) || S_ISBLK(rcinfo.st_mode))) {
541 rcfile_error(S_ISDIR(rcinfo.st_mode) ? _("\"%s\" is a directory") :
542 _("\"%s\" is a device file"), file);
543 return FALSE;
544 } else
545 return TRUE;
546}
547
Benno Schulenberg00389922014-04-04 11:59:03 +0000548#ifndef DISABLE_COLOR
Benno Schulenberg3cb80ff2016-03-12 09:43:10 +0000549/* Read and parse one included syntax file. */
550static void parse_one_include(char *file)
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000551{
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000552 FILE *rcstream;
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000553
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000554 /* Don't open directories, character files, or block files. */
Benno Schulenberg981a1d32016-11-27 17:27:04 +0100555 if (!is_good_file(file))
Benno Schulenberg17629202016-11-26 17:43:36 +0100556 return;
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000557
Benno Schulenberg281a56f2016-11-26 17:41:31 +0100558 /* Open the included syntax file. */
559 rcstream = fopen(file, "rb");
560
561 if (rcstream == NULL) {
562 rcfile_error(_("Error reading %s: %s"), file, strerror(errno));
Chris Allegretta4522ca22009-02-07 00:01:40 +0000563 return;
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000564 }
565
Benno Schulenberg281a56f2016-11-26 17:41:31 +0100566 /* Use the name and line number position of the included syntax file
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000567 * while parsing it, so we can know where any errors in it are. */
Benno Schulenberg38142832014-03-30 20:37:40 +0000568 nanorc = file;
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000569 lineno = 0;
570
Chris Allegrettacc60c3a2008-03-20 05:41:00 +0000571#ifdef DEBUG
Benno Schulenberg38142832014-03-30 20:37:40 +0000572 fprintf(stderr, "Parsing file \"%s\"\n", file);
Chris Allegrettacc60c3a2008-03-20 05:41:00 +0000573#endif
574
Benno Schulenbergde53c532015-04-03 15:57:22 +0000575 parse_rcfile(rcstream, TRUE);
Benno Schulenberg38142832014-03-30 20:37:40 +0000576}
577
Benno Schulenberg3cb80ff2016-03-12 09:43:10 +0000578/* Expand globs in the passed name, and parse the resultant files. */
579void parse_includes(char *ptr)
Benno Schulenberg38142832014-03-30 20:37:40 +0000580{
581 char *option, *nanorc_save = nanorc, *expanded;
582 size_t lineno_save = lineno, i;
583 glob_t files;
584
585 option = ptr;
586 if (*option == '"')
587 option++;
588 ptr = parse_argument(ptr);
589
590 /* Expand tildes first, then the globs. */
591 expanded = real_dir_from_tilde(option);
592
593 if (glob(expanded, GLOB_ERR|GLOB_NOSORT, NULL, &files) == 0) {
594 for (i = 0; i < files.gl_pathc; ++i)
Benno Schulenberg3cb80ff2016-03-12 09:43:10 +0000595 parse_one_include(files.gl_pathv[i]);
596 } else
Benno Schulenberg281a56f2016-11-26 17:41:31 +0100597 rcfile_error(_("Error expanding %s: %s"), option, strerror(errno));
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000598
Benno Schulenberg20011f42014-04-27 11:29:50 +0000599 globfree(&files);
600 free(expanded);
601
Benno Schulenberg3cb80ff2016-03-12 09:43:10 +0000602 /* We're done with the included file(s). Restore the original
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000603 * filename and line number position. */
604 nanorc = nanorc_save;
605 lineno = lineno_save;
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000606}
607
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000608/* Return the short value corresponding to the color named in colorname,
609 * and set bright to TRUE if that color is bright. */
Chris Allegretta22c83ec2013-03-17 22:09:38 +0000610short color_to_short(const char *colorname, bool *bright)
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000611{
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000612 assert(colorname != NULL && bright != NULL);
613
614 if (strncasecmp(colorname, "bright", 6) == 0) {
615 *bright = TRUE;
616 colorname += 6;
617 }
618
619 if (strcasecmp(colorname, "green") == 0)
Benno Schulenberg6e377232016-03-11 16:45:00 +0000620 return COLOR_GREEN;
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000621 else if (strcasecmp(colorname, "red") == 0)
Benno Schulenberg6e377232016-03-11 16:45:00 +0000622 return COLOR_RED;
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000623 else if (strcasecmp(colorname, "blue") == 0)
Benno Schulenberg6e377232016-03-11 16:45:00 +0000624 return COLOR_BLUE;
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000625 else if (strcasecmp(colorname, "white") == 0)
Benno Schulenberg6e377232016-03-11 16:45:00 +0000626 return COLOR_WHITE;
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000627 else if (strcasecmp(colorname, "yellow") == 0)
Benno Schulenberg6e377232016-03-11 16:45:00 +0000628 return COLOR_YELLOW;
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000629 else if (strcasecmp(colorname, "cyan") == 0)
Benno Schulenberg6e377232016-03-11 16:45:00 +0000630 return COLOR_CYAN;
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000631 else if (strcasecmp(colorname, "magenta") == 0)
Benno Schulenberg6e377232016-03-11 16:45:00 +0000632 return COLOR_MAGENTA;
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000633 else if (strcasecmp(colorname, "black") == 0)
Benno Schulenberg6e377232016-03-11 16:45:00 +0000634 return COLOR_BLACK;
635
636 rcfile_error(N_("Color \"%s\" not understood.\n"
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000637 "Valid colors are \"green\", \"red\", \"blue\",\n"
638 "\"white\", \"yellow\", \"cyan\", \"magenta\" and\n"
639 "\"black\", with the optional prefix \"bright\"\n"
640 "for foreground colors."), colorname);
Benno Schulenberg6e377232016-03-11 16:45:00 +0000641 return -1;
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +0000642}
643
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000644/* Parse the color string in the line at ptr, and add it to the current
Benno Schulenberg6ed64622016-03-13 19:37:21 +0000645 * file's associated colors. rex_flags are the regex compilation flags
646 * to use, excluding or including REG_ICASE for case (in)sensitivity. */
647void parse_colors(char *ptr, int rex_flags)
Chris Allegretta08893e02001-11-29 02:42:27 +0000648{
Chris Allegretta22c83ec2013-03-17 22:09:38 +0000649 short fg, bg;
Benno Schulenberg16639942014-05-03 18:24:45 +0000650 bool bright = FALSE;
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100651 char *item;
Chris Allegretta08893e02001-11-29 02:42:27 +0000652
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000653 assert(ptr != NULL);
Chris Allegretta08893e02001-11-29 02:42:27 +0000654
Benno Schulenberg275e9f02016-02-28 20:38:14 +0000655 if (!opensyntax) {
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000656 rcfile_error(
Benno Schulenberg70708122016-03-14 16:09:52 +0000657 N_("A '%s' command requires a preceding 'syntax' command"),
658 "color");
David Lawrence Ramseycee20e52006-04-13 02:43:54 +0000659 return;
660 }
661
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000662 if (*ptr == '\0') {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +0000663 rcfile_error(N_("Missing color name"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000664 return;
Chris Allegretta08893e02001-11-29 02:42:27 +0000665 }
666
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100667 item = ptr;
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000668 ptr = parse_next_word(ptr);
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100669 if (!parse_color_names(item, &fg, &bg, &bright))
Benno Schulenberg16639942014-05-03 18:24:45 +0000670 return;
Chris Allegretta17ec14b2003-02-07 00:19:05 +0000671
David Lawrence Ramseya9d45bb2005-06-09 01:09:00 +0000672 if (*ptr == '\0') {
Benno Schulenbergf1b9ba22016-05-03 09:31:59 +0200673 rcfile_error(N_("Missing regex string after '%s' command"), "color");
David Lawrence Ramseya9d45bb2005-06-09 01:09:00 +0000674 return;
675 }
676
David Lawrence Ramsey5854a872005-06-03 19:10:47 +0000677 /* Now for the fun part. Start adding regexes to individual strings
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000678 * in the colorstrings array, woo! */
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000679 while (ptr != NULL && *ptr != '\0') {
Benno Schulenberg1e5614b2016-07-22 15:48:06 +0200680 colortype *newcolor = NULL;
Benno Schulenberg07f14de2014-05-12 12:11:24 +0000681 /* The container for a color plus its regexes. */
Benno Schulenbergf72e1652016-03-12 10:21:02 +0000682 bool goodstart;
683 /* Whether the start expression was valid. */
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000684 bool expectend = FALSE;
Benno Schulenbergf72e1652016-03-12 10:21:02 +0000685 /* Whether to expect an end= line. */
Chris Allegretta08893e02001-11-29 02:42:27 +0000686
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +0000687 if (strncasecmp(ptr, "start=", 6) == 0) {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000688 ptr += 6;
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000689 expectend = TRUE;
Chris Allegrettaf478f832002-01-18 21:54:35 +0000690 }
691
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000692 if (*ptr != '"') {
David Lawrence Ramsey08c70ae2005-03-14 17:47:17 +0000693 rcfile_error(
694 N_("Regex strings must begin and end with a \" character"));
Chris Allegrettade852622002-09-18 00:28:57 +0000695 ptr = parse_next_regex(ptr);
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000696 continue;
697 }
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000698
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100699 item = ++ptr;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000700 ptr = parse_next_regex(ptr);
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000701 if (ptr == NULL)
702 break;
703
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100704 if (*item == '\0') {
Benno Schulenberga8c1dc12017-01-16 16:28:48 +0100705 rcfile_error(N_("Empty regex string"));
706 goodstart = FALSE;
707 } else
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100708 goodstart = nregcomp(item, rex_flags);
Benno Schulenbergf72e1652016-03-12 10:21:02 +0000709
710 /* If the starting regex is valid, initialize a new color struct,
711 * and hook it in at the tail of the linked list. */
712 if (goodstart) {
Benno Schulenberg6a4d3aa2016-03-04 20:50:38 +0000713 newcolor = (colortype *)nmalloc(sizeof(colortype));
714
Chris Allegrettace452fb2003-02-03 02:56:44 +0000715 newcolor->fg = fg;
716 newcolor->bg = bg;
717 newcolor->bright = bright;
Benno Schulenberg6ed64622016-03-13 19:37:21 +0000718 newcolor->rex_flags = rex_flags;
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000719
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100720 newcolor->start_regex = mallocstrcpy(NULL, item);
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000721 newcolor->start = NULL;
722
David Lawrence Ramseyd2361f02005-07-14 18:33:51 +0000723 newcolor->end_regex = NULL;
Chris Allegrettace452fb2003-02-03 02:56:44 +0000724 newcolor->end = NULL;
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000725
David Lawrence Ramseydb958022005-07-13 20:18:46 +0000726 newcolor->next = NULL;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000727
Benno Schulenbergf72e1652016-03-12 10:21:02 +0000728#ifdef DEBUG
729 fprintf(stderr, "Adding an entry for fg %hd, bg %hd\n", fg, bg);
730#endif
Benno Schulenberg8fbb9222016-03-13 20:05:36 +0000731 if (lastcolor == NULL)
Benno Schulenberg8a5ae212016-03-10 20:36:12 +0000732 live_syntax->color = newcolor;
Benno Schulenberg63d59652016-03-12 11:15:12 +0000733 else
Benno Schulenberg8fbb9222016-03-13 20:05:36 +0000734 lastcolor->next = newcolor;
David Lawrence Ramsey2385c1a2005-07-29 21:42:08 +0000735
Benno Schulenberg8fbb9222016-03-13 20:05:36 +0000736 lastcolor = newcolor;
Benno Schulenbergf72e1652016-03-12 10:21:02 +0000737 }
Chris Allegrettace452fb2003-02-03 02:56:44 +0000738
Benno Schulenbergfa828242016-03-12 09:52:16 +0000739 if (!expectend)
740 continue;
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000741
Benno Schulenbergfa828242016-03-12 09:52:16 +0000742 if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) {
743 rcfile_error(N_("\"start=\" requires a corresponding \"end=\""));
744 return;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000745 }
Benno Schulenbergfa828242016-03-12 09:52:16 +0000746
747 ptr += 4;
748 if (*ptr != '"') {
749 rcfile_error(N_("Regex strings must begin and end with a \" character"));
750 continue;
751 }
752
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100753 item = ++ptr;
Benno Schulenbergfa828242016-03-12 09:52:16 +0000754 ptr = parse_next_regex(ptr);
755 if (ptr == NULL)
Benno Schulenbergcdcd3652016-05-17 11:33:21 +0200756 break;
Benno Schulenbergfa828242016-03-12 09:52:16 +0000757
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100758 if (*item == '\0') {
Benno Schulenberga8c1dc12017-01-16 16:28:48 +0100759 rcfile_error(N_("Empty regex string"));
760 continue;
761 }
762
Benno Schulenbergfa828242016-03-12 09:52:16 +0000763 /* If the start regex was invalid, skip past the end regex
764 * to stay in sync. */
Benno Schulenbergf72e1652016-03-12 10:21:02 +0000765 if (!goodstart)
Benno Schulenbergfa828242016-03-12 09:52:16 +0000766 continue;
767
768 /* If it's valid, save the ending regex string. */
Benno Schulenbergde36e1c2017-01-17 12:33:46 +0100769 if (nregcomp(item, rex_flags))
770 newcolor->end_regex = mallocstrcpy(NULL, item);
Benno Schulenbergfa828242016-03-12 09:52:16 +0000771
772 /* Lame way to skip another static counter. */
773 newcolor->id = live_syntax->nmultis;
774 live_syntax->nmultis++;
Chris Allegrettaf478f832002-01-18 21:54:35 +0000775 }
Chris Allegretta08893e02001-11-29 02:42:27 +0000776}
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000777
Benno Schulenberg16639942014-05-03 18:24:45 +0000778/* Parse the color name, or pair of color names, in combostr. */
779bool parse_color_names(char *combostr, short *fg, short *bg, bool *bright)
780{
781 bool no_fgcolor = FALSE;
782
783 if (combostr == NULL)
Chris Allegretta61523be2014-05-11 03:09:00 +0000784 return FALSE;
Benno Schulenberg16639942014-05-03 18:24:45 +0000785
786 if (strchr(combostr, ',') != NULL) {
787 char *bgcolorname;
788 strtok(combostr, ",");
789 bgcolorname = strtok(NULL, ",");
790 if (bgcolorname == NULL) {
791 /* If we have a background color without a foreground color,
792 * parse it properly. */
793 bgcolorname = combostr + 1;
794 no_fgcolor = TRUE;
795 }
796 if (strncasecmp(bgcolorname, "bright", 6) == 0) {
797 rcfile_error(N_("Background color \"%s\" cannot be bright"), bgcolorname);
Chris Allegretta61523be2014-05-11 03:09:00 +0000798 return FALSE;
Benno Schulenberg16639942014-05-03 18:24:45 +0000799 }
800 *bg = color_to_short(bgcolorname, bright);
801 } else
802 *bg = -1;
803
804 if (!no_fgcolor) {
805 *fg = color_to_short(combostr, bright);
806
807 /* Don't try to parse screwed-up foreground colors. */
808 if (*fg == -1)
Chris Allegretta61523be2014-05-11 03:09:00 +0000809 return FALSE;
Benno Schulenberg16639942014-05-03 18:24:45 +0000810 } else
811 *fg = -1;
812
Chris Allegretta61523be2014-05-11 03:09:00 +0000813 return TRUE;
Benno Schulenberg16639942014-05-03 18:24:45 +0000814}
815
Benno Schulenberg1fba31e2016-02-28 15:16:27 +0000816/* Read regex strings enclosed in double quotes from the line pointed at
817 * by ptr, and store them quoteless in the passed storage place. */
Benno Schulenberged296522016-03-10 11:00:59 +0000818void grab_and_store(const char *kind, char *ptr, regexlisttype **storage)
Benno Schulenberg1fba31e2016-02-28 15:16:27 +0000819{
Benno Schulenberg07f71e62016-02-28 16:36:23 +0000820 regexlisttype *lastthing;
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000821
Benno Schulenbergd08d72a2016-03-11 16:51:15 +0000822 if (!opensyntax) {
823 rcfile_error(
824 N_("A '%s' command requires a preceding 'syntax' command"), kind);
825 return;
826 }
827
Benno Schulenberg2994ea92016-03-10 09:46:21 +0000828 /* The default syntax doesn't take any file matching stuff. */
Benno Schulenberg8a5ae212016-03-10 20:36:12 +0000829 if (strcmp(live_syntax->name, "default") == 0 && *ptr != '\0') {
Benno Schulenberg2994ea92016-03-10 09:46:21 +0000830 rcfile_error(
831 N_("The \"default\" syntax does not accept '%s' regexes"), kind);
832 return;
833 }
834
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000835 if (*ptr == '\0') {
Benno Schulenberg1fba31e2016-02-28 15:16:27 +0000836 rcfile_error(N_("Missing regex string after '%s' command"), kind);
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000837 return;
838 }
839
Benno Schulenberg07f71e62016-02-28 16:36:23 +0000840 lastthing = *storage;
841
842 /* If there was an earlier command, go to the last of those regexes. */
843 while (lastthing != NULL && lastthing->next != NULL)
844 lastthing = lastthing->next;
845
Benno Schulenberg68d94a02016-02-28 17:16:39 +0000846 /* Now gather any valid regexes and add them to the linked list. */
Benno Schulenbergcf4f80d2014-05-12 13:52:50 +0000847 while (*ptr != '\0') {
848 const char *regexstring;
Benno Schulenbergc2148cc2016-02-28 15:47:37 +0000849 regexlisttype *newthing;
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000850
851 if (*ptr != '"') {
852 rcfile_error(
853 N_("Regex strings must begin and end with a \" character"));
Benno Schulenberg3e7591f2016-02-28 11:04:36 +0000854 return;
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000855 }
856
Benno Schulenbergc2148cc2016-02-28 15:47:37 +0000857 regexstring = ++ptr;
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000858 ptr = parse_next_regex(ptr);
859 if (ptr == NULL)
Benno Schulenbergc2148cc2016-02-28 15:47:37 +0000860 return;
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000861
Benno Schulenberg68d94a02016-02-28 17:16:39 +0000862 /* If the regex string is malformed, skip it. */
Benno Schulenberg2f817a62016-03-22 10:42:28 +0000863 if (!nregcomp(regexstring, NANO_REG_EXTENDED | REG_NOSUB))
Benno Schulenberg68d94a02016-02-28 17:16:39 +0000864 continue;
865
866 /* Copy the regex into a struct, and hook this in at the end. */
Benno Schulenbergc2148cc2016-02-28 15:47:37 +0000867 newthing = (regexlisttype *)nmalloc(sizeof(regexlisttype));
Benno Schulenberg68d94a02016-02-28 17:16:39 +0000868 newthing->full_regex = mallocstrcpy(NULL, regexstring);
Benno Schulenberg68d94a02016-02-28 17:16:39 +0000869 newthing->next = NULL;
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000870
Benno Schulenberg68d94a02016-02-28 17:16:39 +0000871 if (lastthing == NULL)
872 *storage = newthing;
873 else
874 lastthing->next = newthing;
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000875
Benno Schulenberg68d94a02016-02-28 17:16:39 +0000876 lastthing = newthing;
Chris Allegrettaf30c1392008-09-21 23:02:30 +0000877 }
878}
Chris Allegretta5575bfa2014-02-24 10:18:15 +0000879
Benno Schulenberg837b4e62016-03-10 10:36:49 +0000880/* Parse and store the name given after a linter/formatter command. */
881void pick_up_name(const char *kind, char *ptr, char **storage)
Chris Allegretta5575bfa2014-02-24 10:18:15 +0000882{
883 assert(ptr != NULL);
884
Benno Schulenberg275e9f02016-02-28 20:38:14 +0000885 if (!opensyntax) {
Chris Allegretta5575bfa2014-02-24 10:18:15 +0000886 rcfile_error(
Benno Schulenberg837b4e62016-03-10 10:36:49 +0000887 N_("A '%s' command requires a preceding 'syntax' command"), kind);
Chris Allegretta5575bfa2014-02-24 10:18:15 +0000888 return;
889 }
890
891 if (*ptr == '\0') {
Benno Schulenberg837b4e62016-03-10 10:36:49 +0000892 rcfile_error(N_("Missing command after '%s'"), kind);
Chris Allegretta5575bfa2014-02-24 10:18:15 +0000893 return;
894 }
895
Benno Schulenberg837b4e62016-03-10 10:36:49 +0000896 free(*storage);
Chris Allegretta5575bfa2014-02-24 10:18:15 +0000897
Benno Schulenberg837b4e62016-03-10 10:36:49 +0000898 /* Allow unsetting the command by using an empty string. */
Chris Allegrettae52eac52014-03-02 05:27:56 +0000899 if (!strcmp(ptr, "\"\""))
Benno Schulenberg837b4e62016-03-10 10:36:49 +0000900 *storage = NULL;
Mike Scalora6a2032f2016-05-25 22:13:50 +0200901 else if (*ptr == '"') {
902 *storage = mallocstrcpy(NULL, ++ptr);
903 char* q = *storage;
904 char* p = *storage;
905 /* Snip out the backslashes of escaped characters. */
906 while (*p != '"') {
907 if (*p == '\0') {
908 rcfile_error(N_("Argument of '%s' lacks closing \""), kind);
909 free(*storage);
910 *storage = NULL;
911 return;
912 } else if (*p == '\\' && *(p + 1) != '\0') {
913 p++;
914 }
915 *q++ = *p++;
916 }
917 *q = '\0';
918 }
Chris Allegrettae52eac52014-03-02 05:27:56 +0000919 else
Benno Schulenberg837b4e62016-03-10 10:36:49 +0000920 *storage = mallocstrcpy(NULL, ptr);
Chris Allegretta5575bfa2014-02-24 10:18:15 +0000921}
Benno Schulenberg00389922014-04-04 11:59:03 +0000922#endif /* !DISABLE_COLOR */
Chris Allegretta5575bfa2014-02-24 10:18:15 +0000923
Benno Schulenberg77023a72016-11-27 16:34:34 +0100924/* Verify that the user has not unmapped every shortcut for a
925 * function that we consider 'vital' (such as "Exit"). */
Chris Allegretta90ee8ee2008-03-20 04:45:55 +0000926static void check_vitals_mapped(void)
927{
928 subnfunc *f;
929 int v;
930#define VITALS 5
Chris Allegretta637daa82011-02-07 14:45:56 +0000931 void (*vitals[VITALS])(void) = { do_exit, do_exit, do_cancel, do_cancel, do_cancel };
Chris Allegretta90ee8ee2008-03-20 04:45:55 +0000932 int inmenus[VITALS] = { MMAIN, MHELP, MWHEREIS, MREPLACE, MGOTOLINE };
933
934 for (v = 0; v < VITALS; v++) {
Benno Schulenberg492e9f62014-06-20 10:48:26 +0000935 for (f = allfuncs; f != NULL; f = f->next) {
936 if (f->scfunc == vitals[v] && f->menus & inmenus[v]) {
937 const sc *s = first_sc_for(inmenus[v], f->scfunc);
938 if (!s) {
939 fprintf(stderr, _("Fatal error: no keys mapped for function "
Benno Schulenbergcdcd3652016-05-17 11:33:21 +0200940 "\"%s\". Exiting.\n"), f->desc);
Benno Schulenberg492e9f62014-06-20 10:48:26 +0000941 fprintf(stderr, _("If needed, use nano with the -I option "
Benno Schulenbergcdcd3652016-05-17 11:33:21 +0200942 "to adjust your nanorc settings.\n"));
943 exit(1);
Benno Schulenberg492e9f62014-06-20 10:48:26 +0000944 }
945 break;
946 }
947 }
Chris Allegretta90ee8ee2008-03-20 04:45:55 +0000948 }
949}
950
David Lawrence Ramsey8f073292006-06-01 20:23:24 +0000951/* Parse the rcfile, once it has been opened successfully at rcstream,
Benno Schulenberg77023a72016-11-27 16:34:34 +0100952 * and close it afterwards. If syntax_only is TRUE, allow the file to
953 * to contain only color syntax commands. */
954void parse_rcfile(FILE *rcstream, bool syntax_only)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000955{
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000956 char *buf = NULL;
957 ssize_t len;
Chris Allegrettadcf5cbb2009-11-27 05:09:56 +0000958 size_t n = 0;
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000959
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000960 while ((len = getline(&buf, &n, rcstream)) > 0) {
961 char *ptr, *keyword, *option;
David Lawrence Ramseydb39a5e2006-05-26 13:38:49 +0000962 int set = 0;
963 size_t i;
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000964
David Lawrence Ramsey03ee3322006-04-12 22:03:47 +0000965 /* Ignore the newline. */
David Lawrence Ramsey5566e442006-05-26 13:49:00 +0000966 if (buf[len - 1] == '\n')
967 buf[len - 1] = '\0';
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000968
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000969 lineno++;
970 ptr = buf;
David Lawrence Ramseyd8640482005-06-12 17:48:46 +0000971 while (isblank(*ptr))
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000972 ptr++;
973
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000974 /* If we have a blank line or a comment, skip to the next
975 * line. */
976 if (*ptr == '\0' || *ptr == '#')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000977 continue;
978
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +0000979 /* Otherwise, skip to the next space. */
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000980 keyword = ptr;
981 ptr = parse_next_word(ptr);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000982
Benno Schulenberg00389922014-04-04 11:59:03 +0000983#ifndef DISABLE_COLOR
Chris Allegrettae52eac52014-03-02 05:27:56 +0000984 /* Handle extending first... */
985 if (strcasecmp(keyword, "extendsyntax") == 0) {
Benno Schulenberg04669b52016-02-29 12:17:53 +0000986 syntaxtype *sint;
Chris Allegrettae52eac52014-03-02 05:27:56 +0000987 char *syntaxname = ptr;
Chris Allegrettae52eac52014-03-02 05:27:56 +0000988
989 ptr = parse_next_word(ptr);
Benno Schulenberg04669b52016-02-29 12:17:53 +0000990
991 for (sint = syntaxes; sint != NULL; sint = sint->next)
992 if (!strcmp(sint->name, syntaxname))
Chris Allegrettae52eac52014-03-02 05:27:56 +0000993 break;
994
Benno Schulenberg04669b52016-02-29 12:17:53 +0000995 if (sint == NULL) {
996 rcfile_error(N_("Could not find syntax \"%s\" to extend"),
997 syntaxname);
Benno Schulenberg85e166b2016-02-29 12:04:22 +0000998 opensyntax = FALSE;
Chris Allegrettae52eac52014-03-02 05:27:56 +0000999 continue;
Chris Allegrettae52eac52014-03-02 05:27:56 +00001000 }
Benno Schulenbergb8aae4d2016-03-11 16:39:27 +00001001
1002 live_syntax = sint;
1003 opensyntax = TRUE;
1004
Benno Schulenberg63d59652016-03-12 11:15:12 +00001005 /* Refind the tail of the color list for this syntax. */
Benno Schulenberg8fbb9222016-03-13 20:05:36 +00001006 lastcolor = sint->color;
1007 if (lastcolor != NULL)
1008 while (lastcolor->next != NULL)
1009 lastcolor = lastcolor->next;
Benno Schulenberg63d59652016-03-12 11:15:12 +00001010
Benno Schulenbergb8aae4d2016-03-11 16:39:27 +00001011 keyword = ptr;
1012 ptr = parse_next_word(ptr);
Chris Allegrettae52eac52014-03-02 05:27:56 +00001013 }
1014
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001015 /* Try to parse the keyword. */
Benno Schulenberg9330aa62016-04-27 10:07:45 +02001016 if (strcasecmp(keyword, "syntax") == 0) {
Benno Schulenberg8fbb9222016-03-13 20:05:36 +00001017 if (opensyntax && lastcolor == NULL)
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +00001018 rcfile_error(N_("Syntax \"%s\" has no color commands"),
Benno Schulenberg8a5ae212016-03-10 20:36:12 +00001019 live_syntax->name);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001020 parse_syntax(ptr);
Chris Allegrettab00d0b92011-02-13 04:23:10 +00001021 }
Benno Schulenbergb8aae4d2016-03-11 16:39:27 +00001022 else if (strcasecmp(keyword, "header") == 0)
1023 grab_and_store("header", ptr, &live_syntax->headers);
Benno Schulenberga997aa62014-03-26 19:25:38 +00001024 else if (strcasecmp(keyword, "magic") == 0)
Benno Schulenbergd7ade1f2015-04-03 17:28:30 +00001025#ifdef HAVE_LIBMAGIC
Benno Schulenberg8a5ae212016-03-10 20:36:12 +00001026 grab_and_store("magic", ptr, &live_syntax->magics);
Benno Schulenbergd7ade1f2015-04-03 17:28:30 +00001027#else
1028 ;
1029#endif
Mike Scalora6a2032f2016-05-25 22:13:50 +02001030 else if (strcasecmp(keyword, "comment") == 0)
1031#ifdef ENABLE_COMMENT
1032 pick_up_name("comment", ptr, &live_syntax->comment);
1033#else
1034 ;
1035#endif
Chris Allegrettaf30c1392008-09-21 23:02:30 +00001036 else if (strcasecmp(keyword, "color") == 0)
Benno Schulenberg2f817a62016-03-22 10:42:28 +00001037 parse_colors(ptr, NANO_REG_EXTENDED);
David Lawrence Ramsey23555f22005-06-27 03:07:10 +00001038 else if (strcasecmp(keyword, "icolor") == 0)
Benno Schulenberg2f817a62016-03-22 10:42:28 +00001039 parse_colors(ptr, NANO_REG_EXTENDED | REG_ICASE);
Benno Schulenberga997aa62014-03-26 19:25:38 +00001040 else if (strcasecmp(keyword, "linter") == 0)
Benno Schulenberg8a5ae212016-03-10 20:36:12 +00001041 pick_up_name("linter", ptr, &live_syntax->linter);
Chris Allegretta4b3f2772015-01-03 07:24:17 +00001042 else if (strcasecmp(keyword, "formatter") == 0)
Benno Schulenbergd7ade1f2015-04-03 17:28:30 +00001043#ifndef DISABLE_SPELLER
Benno Schulenberg8a5ae212016-03-10 20:36:12 +00001044 pick_up_name("formatter", ptr, &live_syntax->formatter);
Benno Schulenbergd7ade1f2015-04-03 17:28:30 +00001045#else
1046 ;
1047#endif
Benno Schulenberg9330aa62016-04-27 10:07:45 +02001048 else if (syntax_only)
1049 rcfile_error(N_("Command \"%s\" not allowed in included file"),
1050 keyword);
1051 else if (strcasecmp(keyword, "include") == 0)
1052 parse_includes(ptr);
1053 else
Benno Schulenberg00389922014-04-04 11:59:03 +00001054#endif /* !DISABLE_COLOR */
Benno Schulenberg9330aa62016-04-27 10:07:45 +02001055 if (strcasecmp(keyword, "set") == 0)
1056 set = 1;
1057 else if (strcasecmp(keyword, "unset") == 0)
1058 set = -1;
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001059 else if (strcasecmp(keyword, "bind") == 0)
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +00001060 parse_binding(ptr, TRUE);
Chris Allegrettae9dee882009-11-21 16:26:59 +00001061 else if (strcasecmp(keyword, "unbind") == 0)
Benno Schulenberg2cdaaac2014-04-08 11:22:41 +00001062 parse_binding(ptr, FALSE);
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001063 else
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +00001064 rcfile_error(N_("Command \"%s\" not understood"), keyword);
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001065
Benno Schulenberg00389922014-04-04 11:59:03 +00001066#ifndef DISABLE_COLOR
Benno Schulenberg8a5ae212016-03-10 20:36:12 +00001067 /* If a syntax was extended, it stops at the end of the command. */
1068 if (live_syntax != syntaxes)
Benno Schulenberg85e166b2016-02-29 12:04:22 +00001069 opensyntax = FALSE;
Chris Allegrettae52eac52014-03-02 05:27:56 +00001070#endif
1071
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001072 if (set == 0)
1073 continue;
1074
1075 if (*ptr == '\0') {
Benno Schulenberg2f00c9d2014-04-07 20:38:29 +00001076 rcfile_error(N_("Missing option"));
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001077 continue;
1078 }
1079
1080 option = ptr;
1081 ptr = parse_next_word(ptr);
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001082
Benno Schulenberg8866f722016-03-14 17:14:35 +00001083 /* Find the just read name among the existing options. */
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001084 for (i = 0; rcopts[i].name != NULL; i++) {
Benno Schulenberg8866f722016-03-14 17:14:35 +00001085 if (strcasecmp(option, rcopts[i].name) == 0)
1086 break;
1087 }
1088
1089 if (rcopts[i].name == NULL) {
1090 rcfile_error(N_("Unknown option \"%s\""), option);
1091 continue;
1092 }
1093
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001094#ifdef DEBUG
Benno Schulenbergd88423e2016-07-13 20:21:50 +02001095 fprintf(stderr, " Option name = \"%s\"\n", rcopts[i].name);
1096 fprintf(stderr, " Flag = %ld\n", rcopts[i].flag);
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001097#endif
Benno Schulenberg8866f722016-03-14 17:14:35 +00001098 /* First handle unsetting. */
1099 if (set == -1) {
Benno Schulenbergcdcd3652016-05-17 11:33:21 +02001100 if (rcopts[i].flag != 0)
Benno Schulenberg8866f722016-03-14 17:14:35 +00001101 UNSET(rcopts[i].flag);
Benno Schulenbergcdcd3652016-05-17 11:33:21 +02001102 else
Benno Schulenberg8866f722016-03-14 17:14:35 +00001103 rcfile_error(N_("Cannot unset option \"%s\""), rcopts[i].name);
1104 continue;
1105 }
1106
1107 /* If the option has a flag, it doesn't take an argument. */
1108 if (rcopts[i].flag != 0) {
1109 SET(rcopts[i].flag);
1110 continue;
1111 }
1112
1113 /* The option doesn't have a flag, so it takes an argument. */
1114 if (*ptr == '\0') {
1115 rcfile_error(N_("Option \"%s\" requires an argument"),
David Lawrence Ramsey08c70ae2005-03-14 17:47:17 +00001116 rcopts[i].name);
Benno Schulenberg8866f722016-03-14 17:14:35 +00001117 continue;
1118 }
David Lawrence Ramsey7bf86e12005-06-08 19:50:02 +00001119
Benno Schulenberg8866f722016-03-14 17:14:35 +00001120 option = ptr;
1121 if (*option == '"')
1122 option++;
1123 ptr = parse_argument(ptr);
1124
1125 option = mallocstrcpy(NULL, option);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001126#ifdef DEBUG
Benno Schulenbergd88423e2016-07-13 20:21:50 +02001127 fprintf(stderr, " Option argument = \"%s\"\n", option);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001128#endif
Benno Schulenberg8866f722016-03-14 17:14:35 +00001129 /* Make sure the option argument is a valid multibyte string. */
1130 if (!is_valid_mbstring(option)) {
Benno Schulenbergecccb8d2016-12-07 21:01:32 +01001131 rcfile_error(N_("Argument is not a valid multibyte string"));
Benno Schulenberg8866f722016-03-14 17:14:35 +00001132 continue;
1133 }
David Lawrence Ramsey30d0a812005-06-13 14:50:32 +00001134
Benno Schulenberg16639942014-05-03 18:24:45 +00001135#ifndef DISABLE_COLOR
Benno Schulenberg8866f722016-03-14 17:14:35 +00001136 if (strcasecmp(rcopts[i].name, "titlecolor") == 0)
1137 specified_color_combo[TITLE_BAR] = option;
Benno Schulenbergde2aa4f2016-10-20 10:07:48 +02001138 else if (strcasecmp(rcopts[i].name, "numbercolor") == 0)
1139 specified_color_combo[LINE_NUMBER] = option;
Benno Schulenberg8866f722016-03-14 17:14:35 +00001140 else if (strcasecmp(rcopts[i].name, "statuscolor") == 0)
1141 specified_color_combo[STATUS_BAR] = option;
1142 else if (strcasecmp(rcopts[i].name, "keycolor") == 0)
1143 specified_color_combo[KEY_COMBO] = option;
1144 else if (strcasecmp(rcopts[i].name, "functioncolor") == 0)
1145 specified_color_combo[FUNCTION_TAG] = option;
1146 else
Benno Schulenberg16639942014-05-03 18:24:45 +00001147#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001148#ifndef DISABLE_OPERATINGDIR
Benno Schulenberg8866f722016-03-14 17:14:35 +00001149 if (strcasecmp(rcopts[i].name, "operatingdir") == 0)
1150 operating_dir = option;
1151 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00001152#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +00001153#ifndef DISABLE_WRAPJUSTIFY
Benno Schulenberg8866f722016-03-14 17:14:35 +00001154 if (strcasecmp(rcopts[i].name, "fill") == 0) {
1155 if (!parse_num(option, &wrap_at)) {
1156 rcfile_error(N_("Requested fill size \"%s\" is invalid"),
1157 option);
1158 wrap_at = -CHARS_FROM_EOL;
Benno Schulenbergeca6fae2017-01-11 09:49:24 +01001159 } else
Benno Schulenberg65bf36b2016-11-13 19:47:15 +01001160 UNSET(NO_WRAP);
Benno Schulenbergeca6fae2017-01-11 09:49:24 +01001161 free(option);
Benno Schulenberg8866f722016-03-14 17:14:35 +00001162 } else
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001163#endif
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001164#ifndef NANO_TINY
Benno Schulenberg8866f722016-03-14 17:14:35 +00001165 if (strcasecmp(rcopts[i].name, "matchbrackets") == 0) {
1166 matchbrackets = option;
1167 if (has_blank_mbchars(matchbrackets)) {
1168 rcfile_error(N_("Non-blank characters required"));
1169 free(matchbrackets);
1170 matchbrackets = NULL;
1171 }
1172 } else if (strcasecmp(rcopts[i].name, "whitespace") == 0) {
1173 whitespace = option;
1174 if (mbstrlen(whitespace) != 2 || strlenpt(whitespace) != 2) {
1175 rcfile_error(N_("Two single-column characters required"));
1176 free(whitespace);
1177 whitespace = NULL;
1178 } else {
1179 whitespace_len[0] = parse_mbchar(whitespace, NULL, NULL);
1180 whitespace_len[1] = parse_mbchar(whitespace +
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001181 whitespace_len[0], NULL, NULL);
Benno Schulenberg8866f722016-03-14 17:14:35 +00001182 }
1183 } else
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001184#endif
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001185#ifndef DISABLE_JUSTIFY
Benno Schulenberg8866f722016-03-14 17:14:35 +00001186 if (strcasecmp(rcopts[i].name, "punct") == 0) {
1187 punct = option;
1188 if (has_blank_mbchars(punct)) {
1189 rcfile_error(N_("Non-blank characters required"));
1190 free(punct);
1191 punct = NULL;
1192 }
1193 } else if (strcasecmp(rcopts[i].name, "brackets") == 0) {
1194 brackets = option;
1195 if (has_blank_mbchars(brackets)) {
1196 rcfile_error(N_("Non-blank characters required"));
1197 free(brackets);
1198 brackets = NULL;
1199 }
1200 } else if (strcasecmp(rcopts[i].name, "quotestr") == 0)
1201 quotestr = option;
1202 else
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001203#endif
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001204#ifndef NANO_TINY
Benno Schulenberg8866f722016-03-14 17:14:35 +00001205 if (strcasecmp(rcopts[i].name, "backupdir") == 0)
1206 backup_dir = option;
1207 else
Benno Schulenberg6f129922016-06-30 18:02:45 +02001208 if (strcasecmp(rcopts[i].name, "wordchars") == 0)
1209 word_chars = option;
1210 else
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001211#endif
1212#ifndef DISABLE_SPELLER
Benno Schulenberg8866f722016-03-14 17:14:35 +00001213 if (strcasecmp(rcopts[i].name, "speller") == 0)
1214 alt_speller = option;
1215 else
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001216#endif
Benno Schulenberg8866f722016-03-14 17:14:35 +00001217 if (strcasecmp(rcopts[i].name, "tabsize") == 0) {
1218 if (!parse_num(option, &tabsize) || tabsize <= 0) {
1219 rcfile_error(N_("Requested tab size \"%s\" is invalid"),
1220 option);
1221 tabsize = -1;
Benno Schulenbergeca6fae2017-01-11 09:49:24 +01001222 }
1223 free(option);
Benno Schulenberg8866f722016-03-14 17:14:35 +00001224 } else
1225 assert(FALSE);
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001226 }
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001227
Benno Schulenberg00389922014-04-04 11:59:03 +00001228#ifndef DISABLE_COLOR
Benno Schulenberg8fbb9222016-03-13 20:05:36 +00001229 if (opensyntax && lastcolor == NULL)
David Lawrence Ramsey8d2d0d92006-05-28 19:00:16 +00001230 rcfile_error(N_("Syntax \"%s\" has no color commands"),
Benno Schulenberg8a5ae212016-03-10 20:36:12 +00001231 live_syntax->name);
David Lawrence Ramsey0b4920a2006-05-26 12:56:30 +00001232
Benno Schulenberg275e9f02016-02-28 20:38:14 +00001233 opensyntax = FALSE;
Benno Schulenberg17864842016-03-11 17:14:30 +00001234#endif
Benno Schulenberg275e9f02016-02-28 20:38:14 +00001235
Chris Allegretta6df90f52002-07-19 01:08:59 +00001236 free(buf);
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001237 fclose(rcstream);
1238 lineno = 0;
David Lawrence Ramseya6d26d02004-07-30 22:52:44 +00001239
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001240 return;
1241}
1242
Benno Schulenbergc1a48422016-11-27 18:21:04 +01001243/* Read and interpret one of the two nanorc files. */
1244void parse_one_nanorc(void)
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001245{
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001246 FILE *rcstream;
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001247
Benno Schulenbergc1a48422016-11-27 18:21:04 +01001248 /* Don't try to open directories nor devices. */
Benno Schulenberg981a1d32016-11-27 17:27:04 +01001249 if (!is_good_file(nanorc))
Benno Schulenbergc1a48422016-11-27 18:21:04 +01001250 return;
David Lawrence Ramsey5fac1712006-04-12 21:44:07 +00001251
Chris Allegrettacc60c3a2008-03-20 05:41:00 +00001252#ifdef DEBUG
Benno Schulenbergc1a48422016-11-27 18:21:04 +01001253 fprintf(stderr, "Going to parse file \"%s\"\n", nanorc);
Chris Allegrettacc60c3a2008-03-20 05:41:00 +00001254#endif
1255
David Lawrence Ramsey979de232006-04-05 21:25:47 +00001256 rcstream = fopen(nanorc, "rb");
Benno Schulenbergc1a48422016-11-27 18:21:04 +01001257
1258 /* If opening the file succeeded, parse it. Otherwise, only
1259 * complain if the file actually exists. */
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001260 if (rcstream != NULL)
Benno Schulenberg77023a72016-11-27 16:34:34 +01001261 parse_rcfile(rcstream, FALSE);
Benno Schulenbergc1a48422016-11-27 18:21:04 +01001262 else if (errno != ENOENT)
1263 rcfile_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
1264}
1265
1266/* First read the system-wide rcfile, then the user's rcfile. */
1267void do_rcfiles(void)
1268{
1269 nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");
1270
1271 /* Process the system-wide nanorc. */
1272 parse_one_nanorc();
Chris Allegrettaff8a68c2002-02-16 20:34:57 +00001273
Benno Schulenberg77023a72016-11-27 16:34:34 +01001274 /* When configured with --disable-wrapping-as-root, turn wrapping off
1275 * for root, so that only root's .nanorc or --fill can turn it on. */
David Lawrence Ramseye53e1252006-07-19 15:50:19 +00001276#ifdef DISABLE_ROOTWRAPPING
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001277 if (geteuid() == NANO_ROOT_UID)
1278 SET(NO_WRAP);
1279#endif
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001280
David Lawrence Ramsey65e6ecb2005-02-08 20:37:53 +00001281 get_homedir();
Chris Allegretta2e39c1c2003-02-13 03:36:15 +00001282
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001283 if (homedir == NULL)
David Lawrence Ramseya27bd652004-08-17 05:23:38 +00001284 rcfile_error(N_("I can't find my home directory! Wah!"));
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001285 else {
Chris Allegrettafaeeb5b2008-08-28 06:13:05 +00001286 nanorc = charealloc(nanorc, strlen(homedir) + strlen(RCFILE_NAME) + 2);
1287 sprintf(nanorc, "%s/%s", homedir, RCFILE_NAME);
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001288
Benno Schulenbergc1a48422016-11-27 18:21:04 +01001289 /* Process the current user's nanorc. */
1290 parse_one_nanorc();
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001291 }
David Lawrence Ramsey9adace82005-03-04 15:09:55 +00001292
Benno Schulenberg925a0012016-11-27 16:40:54 +01001293 check_vitals_mapped();
1294
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001295 free(nanorc);
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001296
Chris Allegrettaa30eb782009-02-09 04:03:20 +00001297 if (errors && !ISSET(QUIET)) {
1298 errors = FALSE;
Benno Schulenbergb8aae4d2016-03-11 16:39:27 +00001299 fprintf(stderr, _("\nPress Enter to continue starting nano.\n"));
Chris Allegrettaa30eb782009-02-09 04:03:20 +00001300 while (getchar() != '\n')
1301 ;
1302 }
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001303}
1304
Benno Schulenbergeea09082014-04-13 20:50:20 +00001305#endif /* !DISABLE_NANORC */