rcfile.c 31.7 KB
Newer Older
1
2
/* $Id$ */
/**************************************************************************
3
 *   rcfile.c                                                             *
4
 *                                                                        *
5
 *   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009   *
6
 *   Free Software Foundation, Inc.                                       *
7
8
 *   This program is free software; you can redistribute it and/or modify *
 *   it under the terms of the GNU General Public License as published by *
9
 *   the Free Software Foundation; either version 3, or (at your option)  *
10
11
 *   any later version.                                                   *
 *                                                                        *
12
13
14
15
 *   This program 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.                             *
16
17
18
 *                                                                        *
 *   You should have received a copy of the GNU General Public License    *
 *   along with this program; if not, write to the Free Software          *
19
20
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA            *
 *   02110-1301, USA.                                                     *
21
22
23
 *                                                                        *
 **************************************************************************/

24
#include "proto.h"
25

26
#include <stdarg.h>
27
28
29
#include <string.h>
#include <stdio.h>
#include <errno.h>
Chris Allegretta's avatar
Chris Allegretta committed
30
#include <unistd.h>
31
#include <ctype.h>
32
33
34

#ifdef ENABLE_NANORC

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
35
static const rcoption rcopts[] = {
36
    {"boldtext", BOLD_TEXT},
37
38
#ifndef DISABLE_JUSTIFY
    {"brackets", 0},
39
#endif
40
    {"const", CONST_UPDATE},
Chris Allegretta's avatar
Chris Allegretta committed
41
#ifndef DISABLE_WRAPJUSTIFY
42
    {"fill", 0},
Chris Allegretta's avatar
Chris Allegretta committed
43
#endif
44
#ifndef DISABLE_MOUSE
45
    {"mouse", USE_MOUSE},
46
47
48
49
#endif
#ifdef ENABLE_MULTIBUFFER
    {"multibuffer", MULTIBUFFER},
#endif
50
    {"morespace", MORE_SPACE},
51
    {"nofollow", NOFOLLOW_SYMLINKS},
52
    {"nohelp", NO_HELP},
53
    {"nonewlines", NO_NEWLINES},
Chris Allegretta's avatar
Chris Allegretta committed
54
#ifndef DISABLE_WRAPPING
55
    {"nowrap", NO_WRAP},
Chris Allegretta's avatar
Chris Allegretta committed
56
#endif
57
#ifndef DISABLE_OPERATINGDIR
58
    {"operatingdir", 0},
59
#endif
Chris Allegretta's avatar
Chris Allegretta committed
60
    {"preserve", PRESERVE},
61
#ifndef DISABLE_JUSTIFY
62
    {"punct", 0},
63
64
    {"quotestr", 0},
#endif
65
    {"rebinddelete", REBIND_DELETE},
66
    {"rebindkeypad", REBIND_KEYPAD},
67
68
69
#ifdef HAVE_REGEX_H
    {"regexp", USE_REGEXP},
#endif
70
#ifndef DISABLE_SPELLER
71
    {"speller", 0},
72
73
74
#endif
    {"suspend", SUSPEND},
    {"tabsize", 0},
75
    {"tempfile", TEMP_FILE},
76
    {"view", VIEW_MODE},
77
#ifndef NANO_TINY
78
79
    {"autoindent", AUTOINDENT},
    {"backup", BACKUP_FILE},
80
    {"allow_insecure_backup", INSECURE_BACKUP},
81
82
83
84
85
    {"backupdir", 0},
    {"backwards", BACKWARDS_SEARCH},
    {"casesensitive", CASE_SENSITIVE},
    {"cut", CUT_TO_END},
    {"historylog", HISTORYLOG},
86
    {"matchbrackets", 0},
87
    {"noconvert", NO_CONVERT},
88
    {"poslog", POS_HISTORY},
89
    {"quiet", QUIET},
90
    {"quickblank", QUICK_BLANK},
91
92
93
    {"smarthome", SMART_HOME},
    {"smooth", SMOOTH_SCROLL},
    {"tabstospaces", TABS_TO_SPACES},
94
    {"undo", UNDOABLE},
95
    {"whitespace", 0},
96
    {"wordbounds", WORD_BOUNDS},
97
    {"softwrap", SOFTWRAP},
98
#endif
99
    {NULL, 0}
100
};
101

102
static bool errors = FALSE;
103
	/* Whether we got any errors while parsing an rcfile. */
104
static size_t lineno = 0;
105
	/* If we did, the line number where the last error occurred. */
106
static char *nanorc = NULL;
107
	/* The path to the rcfile we're parsing. */
108
109
110
#ifdef ENABLE_COLOR
static syntaxtype *endsyntax = NULL;
	/* The end of the list of syntaxes. */
111
112
static exttype *endheader = NULL;
	/* End of header list */
113
114
static colortype *endcolor = NULL;
	/* The end of the color list for the current syntax. */
115

116
#endif
117

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
118
119
120
/* We have an error in some part of the rcfile.  Print the error message
 * on stderr, and then make the user hit Enter to continue starting
 * nano. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
121
void rcfile_error(const char *msg, ...)
122
123
124
{
    va_list ap;

125
126
127
    if (ISSET(QUIET))
	return;

128
    fprintf(stderr, "\n");
129
130
    if (lineno > 0) {
	errors = TRUE;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
131
	fprintf(stderr, _("Error in %s on line %lu: "), nanorc, (unsigned long)lineno);
132
    }
Chris Allegretta's avatar
Chris Allegretta committed
133

134
    va_start(ap, msg);
135
    vfprintf(stderr, _(msg), ap);
136
    va_end(ap);
137
138

    fprintf(stderr, "\n");
139
140
}

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
141
142
143
/* 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. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
144
char *parse_next_word(char *ptr)
145
{
146
    while (!isblank(*ptr) && *ptr != '\0')
147
148
149
	ptr++;

    if (*ptr == '\0')
150
	return ptr;
151

152
153
    /* Null-terminate and advance ptr. */
    *ptr++ = '\0';
154

155
    while (isblank(*ptr))
156
157
158
159
	ptr++;

    return ptr;
}
160

161
162
163
164
/* 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. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
165
166
char *parse_argument(char *ptr)
{
167
    const char *ptr_save = ptr;
Chris Allegretta's avatar
Chris Allegretta committed
168
169
170
171
172
173
174
175
176
177
178
    char *last_quote = NULL;

    assert(ptr != NULL);

    if (*ptr != '"')
	return parse_next_word(ptr);

    do {
	ptr++;
	if (*ptr == '"')
	    last_quote = ptr;
179
    } while (*ptr != '\0');
Chris Allegretta's avatar
Chris Allegretta committed
180
181
182
183
184
185

    if (last_quote == NULL) {
	if (*ptr == '\0')
	    ptr = NULL;
	else
	    *ptr++ = '\0';
186
	rcfile_error(N_("Argument '%s' has an unterminated \""), ptr_save);
Chris Allegretta's avatar
Chris Allegretta committed
187
188
189
190
191
    } else {
	*last_quote = '\0';
	ptr = last_quote + 1;
    }
    if (ptr != NULL)
192
	while (isblank(*ptr))
Chris Allegretta's avatar
Chris Allegretta committed
193
194
195
196
197
	    ptr++;
    return ptr;
}

#ifdef ENABLE_COLOR
198
/* Parse the next regex string from the line at ptr, and return it. */
199
200
char *parse_next_regex(char *ptr)
{
201
202
203
204
    assert(ptr != NULL);

    /* Continue until the end of the line, or a " followed by a space, a
     * blank character, or \0. */
205
    while ((*ptr != '"' || (!isblank(*(ptr + 1)) &&
206
	*(ptr + 1) != '\0')) && *ptr != '\0')
207
208
	ptr++;

209
210
211
    assert(*ptr == '"' || *ptr == '\0');

    if (*ptr == '\0') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
212
213
	rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
214
	return NULL;
215
    }
216

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
217
    /* Null-terminate and advance ptr. */
218
219
    *ptr++ = '\0';

220
    while (isblank(*ptr))
221
222
223
224
225
	ptr++;

    return ptr;
}

226
227
/* Compile the regular expression regex to see if it's valid.  Return
 * TRUE if it is, or FALSE otherwise. */
228
bool nregcomp(const char *regex, int cflags)
229
{
230
    regex_t preg;
231
    const char *r = fixbounds(regex);
232
    int rc = regcomp(&preg, r, REG_EXTENDED | cflags);
233
234

    if (rc != 0) {
235
	size_t len = regerror(rc, &preg, NULL, 0);
236
237
	char *str = charalloc(len);

238
	regerror(rc, &preg, str, len);
239
	rcfile_error(N_("Bad regex \"%s\": %s"), r, str);
240
241
	free(str);
    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
242

243
    regfree(&preg);
244
    return (rc == 0);
245
246
}

247
248
/* Parse the next syntax string from the line at ptr, and add it to the
 * global list of color syntaxes. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
249
void parse_syntax(char *ptr)
250
{
Chris Allegretta's avatar
Chris Allegretta committed
251
    const char *fileregptr = NULL, *nameptr = NULL;
252
    syntaxtype *tmpsyntax;
253
254
    exttype *endext = NULL;
	/* The end of the extensions list for this syntax. */
255

256
    assert(ptr != NULL);
257

258
259
    if (*ptr == '\0') {
	rcfile_error(N_("Missing syntax name"));
260
	return;
261
    }
262
263

    if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
264
265
	rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
266
	return;
267
    }
268

269
270
271
272
273
    ptr++;

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

274
    if (ptr == NULL)
275
	return;
276

277
278
    /* Search for a duplicate syntax name.  If we find one, free it, so
     * that we always use the last syntax with a given name. */
279
280
    for (tmpsyntax = syntaxes; tmpsyntax != NULL;
	tmpsyntax = tmpsyntax->next) {
281
	if (strcmp(nameptr, tmpsyntax->desc) == 0) {
282
283
284
285
286
	    syntaxtype *prev_syntax = tmpsyntax;

	    tmpsyntax = tmpsyntax->next;
	    free(prev_syntax);
	    break;
287
288
289
	}
    }

Chris Allegretta's avatar
Chris Allegretta committed
290
291
    if (syntaxes == NULL) {
	syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype));
292
	endsyntax = syntaxes;
Chris Allegretta's avatar
Chris Allegretta committed
293
    } else {
294
295
	endsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype));
	endsyntax = endsyntax->next;
296
#ifdef DEBUG
297
	fprintf(stderr, "Adding new syntax after first one\n");
298
#endif
Chris Allegretta's avatar
Chris Allegretta committed
299
    }
300

301
302
303
    endsyntax->desc = mallocstrcpy(NULL, nameptr);
    endsyntax->color = NULL;
    endcolor = NULL;
304
    endheader = NULL;
305
    endsyntax->extensions = NULL;
306
    endsyntax->headers = NULL;
307
    endsyntax->magics = NULL;
308
    endsyntax->next = NULL;
309
    endsyntax->nmultis = 0;
310

311
#ifdef DEBUG
312
    fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr);
313
314
#endif

315
316
317
318
319
320
321
    /* The "none" syntax is the same as not having a syntax at all, so
     * we can't assign any extensions or colors to it. */
    if (strcmp(endsyntax->desc, "none") == 0) {
	rcfile_error(N_("The \"none\" syntax is reserved"));
	return;
    }

322
    /* The default syntax should have no associated extensions. */
323
    if (strcmp(endsyntax->desc, "default") == 0 && *ptr != '\0') {
324
325
	rcfile_error(
		N_("The \"default\" syntax must take no extensions"));
326
327
328
	return;
    }

329
330
    /* Now load the extensions into their part of the struct. */
    while (*ptr != '\0') {
331
332
333
	exttype *newext;
	    /* The new extension structure. */

334
	while (*ptr != '"' && *ptr != '\0')
335
336
	    ptr++;

337
	if (*ptr == '\0')
338
	    return;
339

340
341
342
343
	ptr++;

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);
344
345
	if (ptr == NULL)
	    break;
346

347
	newext = (exttype *)nmalloc(sizeof(exttype));
348
349
350
351
352
353

	/* Save the extension regex if it's valid. */
	if (nregcomp(fileregptr, REG_NOSUB)) {
	    newext->ext_regex = mallocstrcpy(NULL, fileregptr);
	    newext->ext = NULL;

354
	    if (endext == NULL)
355
		endsyntax->extensions = newext;
356
357
358
359
	    else
		endext->next = newext;
	    endext = newext;
	    endext->next = NULL;
360
361
	} else
	    free(newext);
362
    }
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432

}


/* Parse the next syntax string from the line at ptr, and add it to the
 * global list of color syntaxes. */
void parse_magictype(char *ptr)
{
#ifdef HAVE_LIBMAGIC
    const char *fileregptr = NULL;
    exttype *endext = NULL;

    assert(ptr != NULL);

    if (syntaxes == NULL) {
	rcfile_error(
		N_("Cannot add a magic string regex without a syntax command"));
	return;
    }

    if (*ptr == '\0') {
	rcfile_error(N_("Missing magic string name"));
	return;
    }

    if (*ptr != '"') {
	rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
	return;
    }

#ifdef DEBUG
    fprintf(stderr, "Starting a magic type: \"%s\"\n", ptr);
#endif

    /* Now load the extensions into their part of the struct. */
    while (*ptr != '\0') {
	exttype *newext;
	    /* The new extension structure. */

	while (*ptr != '"' && *ptr != '\0')
	    ptr++;

	if (*ptr == '\0')
	    return;

	ptr++;

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);
	if (ptr == NULL)
	    break;

	newext = (exttype *)nmalloc(sizeof(exttype));

	/* Save the regex if it's valid. */
	if (nregcomp(fileregptr, REG_NOSUB)) {
	    newext->ext_regex = mallocstrcpy(NULL, fileregptr);
	    newext->ext = NULL;

	    if (endext == NULL)
		endsyntax->magics = newext;
	    else
		endext->next = newext;
	    endext = newext;
	    endext->next = NULL;
	} else
	    free(newext);
    }
#endif /* HAVE_LIBMAGIC */
433
434
}

435
436
437
438
439
440
441
442
443
444
445
446
447
448
int check_bad_binding(sc *s)
{
#define BADLISTLEN 1
    int badtypes[BADLISTLEN] = {META};
    int badseqs[BADLISTLEN] = { 91 };
    int i;

    for (i = 0; i < BADLISTLEN; i++)
        if (s->type == badtypes[i] && s->seq == badseqs[i])
	    return 1;

    return 0;
}

449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
void parse_keybinding(char *ptr)
{
    char *keyptr = NULL, *keycopy = NULL, *funcptr = NULL, *menuptr = NULL;
    sc *s, *newsc;
    int i, menu;

    assert(ptr != NULL);

    if (*ptr == '\0') {
	rcfile_error(N_("Missing key name"));
	return;
    }

    keyptr = ptr;
    ptr = parse_next_word(ptr);
    keycopy = mallocstrcpy(NULL, keyptr);
    for (i = 0; i < strlen(keycopy); i++)
	keycopy[i] = toupper(keycopy[i]);

468
    if (keycopy[0] != 'M' && keycopy[0] != '^' && keycopy[0] != 'F' && keycopy[0] != 'K') {
469
	rcfile_error(
470
		N_("keybindings must begin with \"^\", \"M\", or \"F\""));
471
472
473
474
475
476
	return;
    }

    funcptr = ptr;
    ptr = parse_next_word(ptr);

477
    if (!strcmp(funcptr, "")) {
478
	rcfile_error(
479
		N_("Must specify function to bind key to"));
480
481
482
483
484
485
	return;
    }

    menuptr = ptr;
    ptr = parse_next_word(ptr);

486
    if (!strcmp(menuptr, "")) {
487
488
489
	rcfile_error(
		/* Note to translators, do not translate the word "all"
		   in the sentence below, everything else is fine */
490
		N_("Must specify menu to bind key to (or \"all\")"));
491
492
493
	return;
    }

494
    menu = strtomenu(menuptr);
495
496
    newsc = strtosc(menu, funcptr);
    if (newsc == NULL) {
497
	rcfile_error(
498
		N_("Could not map name \"%s\" to a function"), funcptr);
499
500
501
	return;
    }

502
    if (menu < 1) {
503
	rcfile_error(
504
		N_("Could not map name \"%s\" to a menu"), menuptr);
505
506
	return;
    }
507
508


509
510
#ifdef DEBUG
    fprintf(stderr, "newsc now address %d, menu func assigned = %d, menu = %d\n",
511
	&newsc, newsc->scfunc, menu);
512
513
514
#endif


515
516
517
518
519
520
521
522
523
    newsc->keystr = keycopy;
    newsc->menu = menu;
    newsc->type = strtokeytype(newsc->keystr);
    assign_keyinfo(newsc);
#ifdef DEBUG
    fprintf(stderr, "s->keystr = \"%s\"\n", newsc->keystr);
    fprintf(stderr, "s->seq = \"%d\"\n", newsc->seq);
#endif

524
525
    if (check_bad_binding(newsc)) {
	rcfile_error(
526
		N_("Sorry, keystr \"%s\" is an illegal binding"), newsc->keystr);
527
528
529
	return;
    }

530
531
532
533
    /* now let's have some fun.  Try and delete the other entries
       we found for the same menu, then make this new new
       beginning */
    for (s = sclist; s != NULL; s = s->next) {
Chris Allegretta's avatar
Chris Allegretta committed
534
        if (((s->menu & newsc->menu)) && s->seq == newsc->seq) {
535
536
537
538
539
540
541
542
543
544
	    s->menu &= ~newsc->menu;
#ifdef DEBUG
	    fprintf(stderr, "replaced menu entry %d\n", s->menu);
#endif
	}
    }
    newsc->next = sclist;
    sclist = newsc;
}

545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
/* Let user unbind a sequence from a given (or all) menus */
void parse_unbinding(char *ptr)
{
    char *keyptr = NULL, *keycopy = NULL, *menuptr = NULL;
    sc *s;
    int i, menu;

    assert(ptr != NULL);

    if (*ptr == '\0') {
	rcfile_error(N_("Missing key name"));
	return;
    }

    keyptr = ptr;
    ptr = parse_next_word(ptr);
    keycopy = mallocstrcpy(NULL, keyptr);
    for (i = 0; i < strlen(keycopy); i++)
	keycopy[i] = toupper(keycopy[i]);

#ifdef DEBUG
    fprintf(stderr, "Starting unbinding code");
#endif

    if (keycopy[0] != 'M' && keycopy[0] != '^' && keycopy[0] != 'F' && keycopy[0] != 'K') {
	rcfile_error(
		N_("keybindings must begin with \"^\", \"M\", or \"F\""));
	return;
    }

    menuptr = ptr;
    ptr = parse_next_word(ptr);

    if (!strcmp(menuptr, "")) {
	rcfile_error(
		/* Note to translators, do not translate the word "all"
		   in the sentence below, everything else is fine */
		N_("Must specify menu to bind key to (or \"all\")"));
	return;
    }

    menu = strtomenu(menuptr);
    if (menu < 1) {
	rcfile_error(
		N_("Could not map name \"%s\" to a menu"), menuptr);
	return;
    }


#ifdef DEBUG
    fprintf(stderr, "unbinding \"%s\" from menu = %d\n", keycopy, menu);
#endif

    /* Now find the apropriate entries in the menu to delete */
    for (s = sclist; s != NULL; s = s->next) {
        if (((s->menu & menu)) && !strcmp(s->keystr,keycopy)) {
	    s->menu &= ~menu;
#ifdef DEBUG
	    fprintf(stderr, "deleted menu entry %d\n", s->menu);
#endif
	}
    }
}

609

610
611
612
613
614
/* Read and parse additional syntax files. */
void parse_include(char *ptr)
{
    struct stat rcinfo;
    FILE *rcstream;
615
    char *option, *nanorc_save = nanorc, *expanded;
616
617
618
619
620
621
622
    size_t lineno_save = lineno;

    option = ptr;
    if (*option == '"')
	option++;
    ptr = parse_argument(ptr);

623
624
    /* Can't get the specified file's full path cause it may screw up
	our cwd depending on the parent dirs' permissions, (see Savannah bug 25297) */
625
626

    /* Don't open directories, character files, or block files. */
627
    if (stat(option, &rcinfo) != -1) {
628
629
630
631
	if (S_ISDIR(rcinfo.st_mode) || S_ISCHR(rcinfo.st_mode) ||
		S_ISBLK(rcinfo.st_mode)) {
	    rcfile_error(S_ISDIR(rcinfo.st_mode) ?
		_("\"%s\" is a directory") :
632
		_("\"%s\" is a device file"), option);
633
634
635
	}
    }

636
637
    expanded = real_dir_from_tilde(option);

638
    /* Open the new syntax file. */
639
640
    if ((rcstream = fopen(expanded, "rb")) == NULL) {
	rcfile_error(_("Error reading %s: %s"), expanded,
641
		strerror(errno));
642
	return;
643
644
645
646
    }

    /* Use the name and line number position of the new syntax file
     * while parsing it, so we can know where any errors in it are. */
647
    nanorc = expanded;
648
649
    lineno = 0;

650
#ifdef DEBUG
651
    fprintf(stderr, "Parsing file \"%s\" (expanded from \"%s\")\n", expanded, option);
652
653
#endif

654
655
656
657
658
659
660
661
662
663
664
665
666
    parse_rcfile(rcstream
#ifdef ENABLE_COLOR
	, TRUE
#endif
	);

    /* We're done with the new syntax file.  Restore the original
     * filename and line number position. */
    nanorc = nanorc_save;
    lineno = lineno_save;

}

667
668
/* Return the short value corresponding to the color named in colorname,
 * and set bright to TRUE if that color is bright. */
669
COLORWIDTH color_to_short(const char *colorname, bool *bright)
670
{
671
    COLORWIDTH mcolor = -1;
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705

    assert(colorname != NULL && bright != NULL);

    if (strncasecmp(colorname, "bright", 6) == 0) {
	*bright = TRUE;
	colorname += 6;
    }

    if (strcasecmp(colorname, "green") == 0)
	mcolor = COLOR_GREEN;
    else if (strcasecmp(colorname, "red") == 0)
	mcolor = COLOR_RED;
    else if (strcasecmp(colorname, "blue") == 0)
	mcolor = COLOR_BLUE;
    else if (strcasecmp(colorname, "white") == 0)
	mcolor = COLOR_WHITE;
    else if (strcasecmp(colorname, "yellow") == 0)
	mcolor = COLOR_YELLOW;
    else if (strcasecmp(colorname, "cyan") == 0)
	mcolor = COLOR_CYAN;
    else if (strcasecmp(colorname, "magenta") == 0)
	mcolor = COLOR_MAGENTA;
    else if (strcasecmp(colorname, "black") == 0)
	mcolor = COLOR_BLACK;
    else
	rcfile_error(N_("Color \"%s\" not understood.\n"
		"Valid colors are \"green\", \"red\", \"blue\",\n"
		"\"white\", \"yellow\", \"cyan\", \"magenta\" and\n"
		"\"black\", with the optional prefix \"bright\"\n"
		"for foreground colors."), colorname);

    return mcolor;
}

706
707
708
/* Parse the color string in the line at ptr, and add it to the current
 * file's associated colors.  If icase is TRUE, treat the color string
 * as case insensitive. */
709
void parse_colors(char *ptr, bool icase)
710
{
711
    COLORWIDTH fg, bg;
712
    bool bright = FALSE, no_fgcolor = FALSE;
Chris Allegretta's avatar
Chris Allegretta committed
713
    char *fgstr;
714

715
    assert(ptr != NULL);
716

717
718
    if (syntaxes == NULL) {
	rcfile_error(
719
		N_("Cannot add a color command without a syntax command"));
720
721
722
	return;
    }

723
    if (*ptr == '\0') {
724
	rcfile_error(N_("Missing color name"));
725
	return;
726
727
    }

728
729
730
731
    fgstr = ptr;
    ptr = parse_next_word(ptr);

    if (strchr(fgstr, ',') != NULL) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
732
	char *bgcolorname;
733

734
	strtok(fgstr, ",");
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
735
	bgcolorname = strtok(NULL, ",");
736
737
738
739
740
741
	if (bgcolorname == NULL) {
	    /* If we have a background color without a foreground color,
	     * parse it properly. */
	    bgcolorname = fgstr + 1;
	    no_fgcolor = TRUE;
	}
742
	if (strncasecmp(bgcolorname, "bright", 6) == 0) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
743
	    rcfile_error(
744
		N_("Background color \"%s\" cannot be bright"),
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
745
		bgcolorname);
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
746
747
	    return;
	}
748
	bg = color_to_short(bgcolorname, &bright);
749
    } else
Chris Allegretta's avatar
Chris Allegretta committed
750
	bg = -1;
751

752
    if (!no_fgcolor) {
753
	fg = color_to_short(fgstr, &bright);
754

755
756
757
758
759
	/* Don't try to parse screwed-up foreground colors. */
	if (fg == -1)
	    return;
    } else
	fg = -1;
760

761
    if (*ptr == '\0') {
762
	rcfile_error(N_("Missing regex string"));
763
764
765
	return;
    }

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
766
    /* Now for the fun part.  Start adding regexes to individual strings
767
768
     * in the colorstrings array, woo! */
    while (ptr != NULL && *ptr != '\0') {
769
770
	colortype *newcolor;
	    /* The new color structure. */
771
	bool cancelled = FALSE;
772
	    /* The start expression was bad. */
773
774
	bool expectend = FALSE;
	    /* Do we expect an end= line? */
775

776
	if (strncasecmp(ptr, "start=", 6) == 0) {
777
	    ptr += 6;
778
	    expectend = TRUE;
779
780
781
	}

	if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
782
783
	    rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
784
	    ptr = parse_next_regex(ptr);
785
786
	    continue;
	}
787

788
	ptr++;
789

790
791
	fgstr = ptr;
	ptr = parse_next_regex(ptr);
792
793
794
	if (ptr == NULL)
	    break;

795
	newcolor = (colortype *)nmalloc(sizeof(colortype));
796

797
798
799
	/* Save the starting regex string if it's valid, and set up the
	 * color information. */
	if (nregcomp(fgstr, icase ? REG_ICASE : 0)) {
800
801
802
	    newcolor->fg = fg;
	    newcolor->bg = bg;
	    newcolor->bright = bright;
803
	    newcolor->icase = icase;
804
805
806
807

	    newcolor->start_regex = mallocstrcpy(NULL, fgstr);
	    newcolor->start = NULL;

808
	    newcolor->end_regex = NULL;
809
	    newcolor->end = NULL;
810

811
	    newcolor->next = NULL;
812

813
814
	    if (endcolor == NULL) {
		endsyntax->color = newcolor;
815
#ifdef DEBUG
816
		fprintf(stderr, "Starting a new colorstring for fg %hd, bg %hd\n", fg, bg);
817
#endif
818
	    } else {
Chris Allegretta's avatar
Chris Allegretta committed
819
#ifdef DEBUG
820
		fprintf(stderr, "Adding new entry for fg %hd, bg %hd\n", fg, bg);
Chris Allegretta's avatar
Chris Allegretta committed
821
#endif
822
		endcolor->next = newcolor;
823
	    }
824

825
	    endcolor = newcolor;
826
827
828
	} else {
	    free(newcolor);
	    cancelled = TRUE;
829
	}
Chris Allegretta's avatar
Chris Allegretta committed
830

831
	if (expectend) {
832
	    if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
833
834
		rcfile_error(
			N_("\"start=\" requires a corresponding \"end=\""));
835
836
837
838
		return;
	    }
	    ptr += 4;
	    if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
839
840
		rcfile_error(
			N_("Regex strings must begin and end with a \" character"));
841
		continue;
842
	    }
843

844
845
	    ptr++;

846
	    fgstr = ptr;
847
	    ptr = parse_next_regex(ptr);
848
849
	    if (ptr == NULL)
		break;
850
851
852
853
854

	    /* If the start regex was invalid, skip past the end regex to
	     * stay in sync. */
	    if (cancelled)
		continue;
855

856
857
858
	    /* Save the ending regex string if it's valid. */
	    newcolor->end_regex = (nregcomp(fgstr, icase ? REG_ICASE :
		0)) ? mallocstrcpy(NULL, fgstr) : NULL;
859
860

	    /* Lame way to skip another static counter */
861
	    newcolor->id = endsyntax->nmultis;
862
            endsyntax->nmultis++;
Chris Allegretta's avatar
Chris Allegretta committed
863
	}
864
    }
865
}
866
867
868
869

/* Parse the headers (1st line) of the file which may influence the regex used. */
void parse_headers(char *ptr)
{
870
    char *regstr;
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928

    assert(ptr != NULL);

    if (syntaxes == NULL) {
	rcfile_error(
		N_("Cannot add a header regex without a syntax command"));
	return;
    }

    if (*ptr == '\0') {
	rcfile_error(N_("Missing regex string"));
	return;
    }

    /* Now for the fun part.  Start adding regexes to individual strings
     * in the colorstrings array, woo! */
    while (ptr != NULL && *ptr != '\0') {
	exttype *newheader;
	    /* The new color structure. */

	if (*ptr != '"') {
	    rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
	    ptr = parse_next_regex(ptr);
	    continue;
	}

	ptr++;

	regstr = ptr;
	ptr = parse_next_regex(ptr);
	if (ptr == NULL)
	    break;

	newheader = (exttype *)nmalloc(sizeof(exttype));

	/* Save the regex string if it's valid */
	if (nregcomp(regstr, 0)) {
	    newheader->ext_regex = mallocstrcpy(NULL, regstr);
	    newheader->ext = NULL;
	    newheader->next = NULL;

#ifdef DEBUG
	     fprintf(stderr, "Starting a new header entry: %s\n", newheader->ext_regex);
#endif

	    if (endheader == NULL) {
		endsyntax->headers = newheader;
	    } else {
		endheader->next = newheader;
	    }

	    endheader = newheader;
	} else
	    free(newheader);

    }
}
929
#endif /* ENABLE_COLOR */
930

931
932
933
934
935
936
937
/* Check whether the user has unmapped every shortcut for a
sequence we consider 'vital', like the exit function */
static void check_vitals_mapped(void)
{
    subnfunc *f;
    int v;
#define VITALS 5
938
    void (*vitals[VITALS])(void) = { do_exit, do_exit, do_cancel, do_cancel, do_cancel };
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
    int inmenus[VITALS] = { MMAIN, MHELP, MWHEREIS, MREPLACE, MGOTOLINE };

    for  (v = 0; v < VITALS; v++) {
       for (f = allfuncs; f != NULL; f = f->next) {
           if (f->scfunc == vitals[v] && f->menus & inmenus[v]) {
               const sc *s = first_sc_for(inmenus[v], f->scfunc);
               if (!s) {
                   rcfile_error(N_("Fatal error: no keys mapped for function \"%s\""),
                       f->desc);
                   fprintf(stderr, N_("Exiting.  Please use nano with the -I option if needed to adjust your nanorc settings\n"));
                   exit(1);
               }
           break;
           }
       }
    }
}

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
957
958
959
/* Parse the rcfile, once it has been opened successfully at rcstream,
 * and close it afterwards.  If syntax_only is TRUE, only allow the file
 * to contain color syntax commands: syntax, color, and icolor. */
960
961
962
963
964
void parse_rcfile(FILE *rcstream
#ifdef ENABLE_COLOR
	, bool syntax_only
#endif
	)
965
{
966
967
    char *buf = NULL;
    ssize_t len;
968
    size_t n = 0;
969
970
971

    while ((len = getline(&buf, &n, rcstream)) > 0) {
	char *ptr, *keyword, *option;
972
973
	int set = 0;
	size_t i;
974

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
975
	/* Ignore the newline. */
976
977
	if (buf[len - 1] == '\n')
	    buf[len - 1] = '\0';
978
979
980

	lineno++;
	ptr = buf;
981
	while (isblank(*ptr))
982
983
	    ptr++;

984
985
986
	/* If we have a blank line or a comment, skip to the next
	 * line. */
	if (*ptr == '\0' || *ptr == '#')
987
988
	    continue;

989
	/* Otherwise, skip to the next space. */
990
991
992
	keyword = ptr;
	ptr = parse_next_word(ptr);

993
	/* Try to parse the keyword. */
994
	if (strcasecmp(keyword, "set") == 0) {
995
#ifdef ENABLE_COLOR
996
997
	    if (syntax_only)
		rcfile_error(
998
			N_("Command \"%s\" not allowed in included file"),
999
1000
1001
1002
1003
1004
1005
1006
			keyword);
	    else
#endif
		set = 1;
	} else if (strcasecmp(keyword, "unset") == 0) {
#ifdef ENABLE_COLOR
	    if (syntax_only)
		rcfile_error(
1007
			N_("Command \"%s\" not allowed in included file"),
1008
1009
1010
1011
1012
1013
1014
1015
1016
			keyword);
	    else
#endif
		set = -1;
	}
#ifdef ENABLE_COLOR
	else if (strcasecmp(keyword, "include") == 0) {
	    if (syntax_only)
		rcfile_error(
1017
			N_("Command \"%s\" not allowed in included file"),
1018
1019
1020
			keyword);
	    else
		parse_include(ptr);
1021
1022
	} else if (strcasecmp(keyword, "syntax") == 0) {
	    if (endsyntax != NULL && endcolor == NULL)
1023
		rcfile_error(N_("Syntax \"%s\" has no color commands"),
1024
			endsyntax->desc);
Chris Allegretta's avatar
Chris Allegretta committed
1025
	    parse_syntax(ptr);
1026
1027
1028
	}
	else if (strcasecmp(keyword, "magic") == 0) {
 	    parse_magictype(ptr);
1029
1030
1031
	} else if (strcasecmp(keyword, "header") == 0)
	    parse_headers(ptr);
	else if (strcasecmp(keyword, "color") == 0)
1032
1033
1034
	    parse_colors(ptr, FALSE);
	else if (strcasecmp(keyword, "icolor") == 0)
	    parse_colors(ptr, TRUE);
1035
1036
	else if (strcasecmp(keyword, "bind") == 0)
	    parse_keybinding(ptr);
1037
1038
	else if (strcasecmp(keyword, "unbind") == 0)
	    parse_unbinding(ptr);
1039
1040
#endif /* ENABLE_COLOR */
	else
1041
	    rcfile_error(N_("Command \"%s\" not understood"), keyword);
1042
1043
1044
1045
1046
1047

	if (set == 0)
	    continue;

	if (*ptr == '\0') {
	    rcfile_error(N_("Missing flag"));
1048
1049
1050
1051
1052
1053
	    continue;
	}

	option = ptr;
	ptr = parse_next_word(ptr);

1054
1055
	for (i = 0; rcopts[i].name != NULL; i++) {
	    if (strcasecmp(option, rcopts[i].name) == 0) {
1056
#ifdef DEBUG
1057
1058
1059
1060
1061
1062
1063
1064
1065
		fprintf(stderr, "parse_rcfile(): name = \"%s\"\n", rcopts[i].name);
#endif
		if (set == 1) {
		    if (rcopts[i].flag != 0)
			/* This option has a flag, so it doesn't take an
			 * argument. */
			SET(rcopts[i].flag);
		    else {
			/* This option doesn't have a flag, so it takes
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1066
			 * an argument. */
1067
			if (*ptr == '\0') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1068
			    rcfile_error(
1069
				N_("Option \"%s\" requires an argument"),
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1070
				rcopts[i].name);
1071
1072
1073
1074
1075
1076
			    break;
			}
			option = ptr;
			if (*option == '"')
			    option++;
			ptr = parse_argument(ptr);
1077

1078
			option = mallocstrcpy(NULL, option);
Chris Allegretta's avatar
Chris Allegretta committed
1079
#ifdef DEBUG
1080
			fprintf(stderr, "option = \"%s\"\n", option);
Chris Allegretta's avatar
Chris Allegretta committed
1081
#endif
1082
1083
1084
1085
1086
1087
1088
1089
1090

			/* Make sure option is a valid multibyte
			 * string. */
			if (!is_valid_mbstring(option)) {
			    rcfile_error(
				N_("Option is not a valid multibyte string"));
			    break;
			}

Chris Allegretta's avatar
Chris Allegretta committed
1091
#ifndef DISABLE_OPERATINGDIR
1092
			if (strcasecmp(rcopts[i].name, "operatingdir") == 0)
1093
			    operating_dir = option;
1094
			else
Chris Allegretta's avatar
Chris Allegretta committed
1095
#endif
1096
#ifndef DISABLE_WRAPJUSTIFY
1097
1098
			if (strcasecmp(rcopts[i].name, "fill") == 0) {
			    if (!parse_num(option, &wrap_at)) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1099
				rcfile_error(
1100
					N_("Requested fill size \"%s\" is invalid"),
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1101
					option);
1102
				wrap_at = -CHARS_FROM_EOL;
1103
1104
			    } else
				free(option);
1105
			} else
Chris Allegretta's avatar
Chris Allegretta committed
1106
#endif
1107
#ifndef NANO_TINY
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
			if (strcasecmp(rcopts[i].name,
				"matchbrackets") == 0) {
			    matchbrackets = option;
			    if (has_blank_mbchars(matchbrackets)) {
				rcfile_error(
					N_("Non-blank characters required"));
				free(matchbrackets);
				matchbrackets = NULL;
			    }
			} else if (strcasecmp(rcopts[i].name,
				"whitespace") == 0) {
1119
			    whitespace = option;
1120
1121
			    if (mbstrlen(whitespace) != 2 ||
				strlenpt(whitespace) != 2) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1122
1123
				rcfile_error(
					N_("Two single-column characters required"));
1124
1125
				free(whitespace);
				whitespace = NULL;
1126
1127
1128
			    } else {
				whitespace_len[0] =
					parse_mbchar(whitespace, NULL,
1129
					NULL);
1130
1131
				whitespace_len[1] =
					parse_mbchar(whitespace +
1132
					whitespace_len[0], NULL, NULL);
1133
1134
			    }
			} else
1135
#endif
1136
#ifndef DISABLE_JUSTIFY
1137
			if (strcasecmp(rcopts[i].name, "punct") == 0) {
1138
			    punct = option;
1139
			    if (has_blank_mbchars(punct)) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1140
				rcfile_error(
1141
					N_("Non-blank characters required"));
1142
1143
1144
				free(punct);
				punct = NULL;
			    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1145
1146
			} else if (strcasecmp(rcopts[i].name,
				"brackets") == 0) {
1147
			    brackets = option;
1148
			    if (has_blank_mbchars(brackets)) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1149
				rcfile_error(
1150
					N_("Non-blank characters required"));
1151
1152
1153
				free(brackets);
				brackets = NULL;
			    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1154
1155
			} else if (strcasecmp(rcopts[i].name,
				"quotestr") == 0)
1156
			    quotestr = option;
1157
			else
1158
#endif
1159
#ifndef NANO_TINY
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1160
1161
			if (strcasecmp(rcopts[i].name,
				"backupdir") == 0)
1162
			    backup_dir = option;
1163
			else
1164
#endif
1165
#ifndef DISABLE_SPELLER
1166
			if (strcasecmp(rcopts[i].name, "speller") == 0)
1167
			    alt_speller = option;
1168
1169
			else
#endif
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1170
1171
1172
1173
1174
			if (strcasecmp(rcopts[i].name,
				"tabsize") == 0) {
			    if (!parse_num(option, &tabsize) ||
				tabsize <= 0) {
				rcfile_error(
1175
					N_("Requested tab size \"%s\" is invalid"),
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1176
					option);
1177
				tabsize = -1;
1178
1179
			    } else
				free(option);
1180
			} else
1181
1182
			    assert(FALSE);
		    }
1183
#ifdef DEBUG
1184
		    fprintf(stderr, "flag = %ld\n", rcopts[i].flag);
1185
#endif
1186
1187
1188
		} else if (rcopts[i].flag != 0)
		    UNSET(rcopts[i].flag);
		else
1189
		    rcfile_error(N_("Cannot unset flag \"%s\""),
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1190
			rcopts[i].name);
1191
1192
1193
		/* Looks like we still need this specific hack for undo */
		if (strcasecmp(rcopts[i].name, "undo") == 0)
		    shortcut_init(0);
1194
		break;
1195
1196
	    }
	}
1197
	if (rcopts[i].name == NULL)
1198
	    rcfile_error(N_("Unknown flag \"%s\""), option);
1199
    }
1200

1201
#ifdef ENABLE_COLOR
1202
    if (endsyntax != NULL && endcolor == NULL)
1203
	rcfile_error(N_("Syntax \"%s\" has no color commands"),
1204
		endsyntax->desc);
1205
#endif
1206

Chris Allegretta's avatar
Chris Allegretta committed
1207
    free(buf);
1208
1209
    fclose(rcstream);
    lineno = 0;
1210

Chris Allegretta's avatar
Chris Allegretta committed
1211
    check_vitals_mapped();
1212
1213
1214
    return;
}

1215
/* The main rcfile function.  It tries to open the system-wide rcfile,
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1216
 * followed by the current user's rcfile. */
1217
1218
void do_rcfile(void)
{
1219
    struct stat rcinfo;
1220
1221
    FILE *rcstream;

1222
    nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232

    /* Don't open directories, character files, or block files. */
    if (stat(nanorc, &rcinfo) != -1) {
	if (S_ISDIR(rcinfo.st_mode) || S_ISCHR(rcinfo.st_mode) ||
		S_ISBLK(rcinfo.st_mode))
	    rcfile_error(S_ISDIR(rcinfo.st_mode) ?
		_("\"%s\" is a directory") :
		_("\"%s\" is a device file"), nanorc);
    }

1233
1234
1235
1236
#ifdef DEBUG
    fprintf(stderr, "Parsing file \"%s\"\n", nanorc);
#endif

1237
    /* Try to open the system-wide nanorc. */
1238
    rcstream = fopen(nanorc, "rb");
1239
    if (rcstream != NULL)
1240
1241
1242
1243
1244
	parse_rcfile(rcstream
#ifdef ENABLE_COLOR
		, FALSE
#endif
		);
1245

1246
#ifdef DISABLE_ROOTWRAPPING
1247
    /* We've already read SYSCONFDIR/nanorc, if it's there.  If we're
1248
1249
     * root, and --disable-wrapping-as-root is used, turn wrapping off
     * now. */
1250
1251
1252
    if (geteuid() == NANO_ROOT_UID)
	SET(NO_WRAP);
#endif
Chris Allegretta's avatar
Chris Allegretta committed
1253

1254
    get_homedir();
1255

1256
    if (homedir == NULL)
1257
	rcfile_error(N_("I can't find my home directory!  Wah!"));
1258
    else {
1259
1260
1261
1262
1263
#ifndef RCFILE_NAME
#define RCFILE_NAME ".nanorc"
#endif
	nanorc = charealloc(nanorc, strlen(homedir) + strlen(RCFILE_NAME) + 2);
	sprintf(nanorc, "%s/%s", homedir, RCFILE_NAME);
1264

1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
	/* Don't open directories, character files, or block files. */
	if (stat(nanorc, &rcinfo) != -1) {
	    if (S_ISDIR(rcinfo.st_mode) || S_ISCHR(rcinfo.st_mode) ||
		S_ISBLK(rcinfo.st_mode))
		rcfile_error(S_ISDIR(rcinfo.st_mode) ?
			_("\"%s\" is a directory") :
			_("\"%s\" is a device file"), nanorc);
	}

	/* Try to open the current user's nanorc. */
	rcstream = fopen(nanorc, "rb");
1276
	if (rcstream == NULL) {
1277
1278
	    /* Don't complain about the file's not existing. */
	    if (errno != ENOENT)
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1279
1280
		rcfile_error(N_("Error reading %s: %s"), nanorc,
			strerror(errno));
1281
	} else
1282
1283
1284
1285
1286
	    parse_rcfile(rcstream
#ifdef ENABLE_COLOR
		, FALSE
#endif
		);
1287
    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1288

1289
1290
    free(nanorc);
    nanorc = NULL;
1291

1292
1293
1294
1295
1296
1297
1298
1299
    if (errors && !ISSET(QUIET)) {
	errors = FALSE;
	fprintf(stderr,
		_("\nPress Enter to continue starting nano.\n"));
	while (getchar() != '\n')
	    ;
    }

1300
1301
1302
#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
1303
1304
}

1305
#endif /* ENABLE_NANORC */