rcfile.c 17.1 KB
Newer Older
1
2
/* $Id$ */
/**************************************************************************
3
 *   rcfile.c                                                             *
4
 *                                                                        *
5
 *   Copyright (C) 1999-2005 Chris Allegretta                             *
6
7
 *   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 *
8
 *   the Free Software Foundation; either version 2, or (at your option)  *
9
10
11
12
13
14
15
16
17
18
19
20
21
 *   any later version.                                                   *
 *                                                                        *
 *   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.                         *
 *                                                                        *
 *   You should have received a copy of the GNU General Public License    *
 *   along with this program; if not, write to the Free Software          *
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
 *                                                                        *
 **************************************************************************/

22
23
24
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
25

26
#include <stdlib.h>
27
#include <stdarg.h>
28
29
30
#include <string.h>
#include <stdio.h>
#include <errno.h>
Chris Allegretta's avatar
Chris Allegretta committed
31
#include <unistd.h>
32
#include <ctype.h>
Chris Allegretta's avatar
Chris Allegretta committed
33
#include <assert.h>
34
35
36
37
#include "proto.h"

#ifdef ENABLE_NANORC

38
const static rcoption rcopts[] = {
39
#ifndef NANO_SMALL
40
    {"autoindent", AUTOINDENT},
41
    {"backup", BACKUP_FILE},
42
    {"backupdir", 0},
43
44
45
#endif
#ifndef DISABLE_JUSTIFY
    {"brackets", 0},
46
47
48
#endif
    {"const", CONSTUPDATE},
#ifndef NANO_SMALL
49
    {"cut", CUT_TO_END},
50
#endif
Chris Allegretta's avatar
Chris Allegretta committed
51
#ifndef DISABLE_WRAPJUSTIFY
52
    {"fill", 0},
Chris Allegretta's avatar
Chris Allegretta committed
53
#endif
54
55
56
#ifndef NANO_SMALL
    {"historylog", HISTORYLOG},
#endif
57
#ifndef DISABLE_MOUSE
58
    {"mouse", USE_MOUSE},
59
60
61
62
#endif
#ifdef ENABLE_MULTIBUFFER
    {"multibuffer", MULTIBUFFER},
#endif
63
    {"morespace", MORE_SPACE},
64
65
66
#ifndef NANO_SMALL
    {"noconvert", NO_CONVERT},
#endif
67
    {"nofollow", NOFOLLOW_SYMLINKS},
68
    {"nohelp", NO_HELP},
Chris Allegretta's avatar
Chris Allegretta committed
69
#ifndef DISABLE_WRAPPING
70
    {"nowrap", NO_WRAP},
Chris Allegretta's avatar
Chris Allegretta committed
71
#endif
72
#ifndef DISABLE_OPERATINGDIR
73
    {"operatingdir", 0},
74
#endif
Chris Allegretta's avatar
Chris Allegretta committed
75
    {"preserve", PRESERVE},
76
#ifndef DISABLE_JUSTIFY
77
    {"punct", 0},
78
79
    {"quotestr", 0},
#endif
80
    {"rebinddelete", REBIND_DELETE},
81
82
83
84
#ifdef HAVE_REGEX_H
    {"regexp", USE_REGEXP},
#endif
#ifndef NANO_SMALL
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
85
    {"smarthome", SMART_HOME},
86
87
88
    {"smooth", SMOOTHSCROLL},
#endif
#ifndef DISABLE_SPELLER
89
    {"speller", 0},
90
91
92
#endif
    {"suspend", SUSPEND},
    {"tabsize", 0},
93
    {"tempfile", TEMP_FILE},
94
    {"view", VIEW_MODE},
95
96
97
#ifndef NANO_SMALL
    {"whitespace", 0},
#endif
98
    {NULL, 0}
99
};
100

101
static bool errors = FALSE;
102
static int lineno = 0;
103
104
105
106
107
108
109
static char *nanorc = NULL;
#ifdef ENABLE_COLOR
static syntaxtype *endsyntax = NULL;
	/* The end of the list of syntaxes. */
static colortype *endcolor = NULL;
	/* The end of the color list for the current syntax. */
#endif
110

111
112
/* We have an error in some part of the rcfile.  Put it on stderr and
 * make the user hit return to continue starting up nano. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
113
void rcfile_error(const char *msg, ...)
114
115
116
117
{
    va_list ap;

    fprintf(stderr, "\n");
118
119
    if (lineno > 0) {
	errors = TRUE;
Chris Allegretta's avatar
Chris Allegretta committed
120
	fprintf(stderr, _("Error in %s on line %d: "), nanorc, lineno);
121
    }
Chris Allegretta's avatar
Chris Allegretta committed
122

123
    va_start(ap, msg);
124
    vfprintf(stderr, _(msg), ap);
125
    va_end(ap);
126
127

    fprintf(stderr, "\n");
128
129
}

130
131
/* Parse the next word from the string.  Return points to '\0' if we hit
 * the end of the line. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
132
char *parse_next_word(char *ptr)
133
{
134
    while (!is_blank_char(*ptr) && *ptr != '\0')
135
136
137
	ptr++;

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

140
141
    /* Null-terminate and advance ptr. */
    *ptr++ = '\0';
142

143
    while (is_blank_char(*ptr))
144
145
146
147
	ptr++;

    return ptr;
}
148

149
150
151
152
153
154
155
/* The keywords operatingdir, backupdir, fill, tabsize, speller, punct,
 * brackets, quotestr, and whitespace take an argument when set.  Among
 * these, operatingdir, backupdir, speller, punct, brackets, quotestr,
 * and whitespace have to allow tabs and spaces in the argument.  Thus,
 * if the next word starts with a ", we say it ends with the last " of
 * the line.  Otherwise, the word is interpreted as usual.  That is so
 * the arguments can contain "s too. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
156
157
char *parse_argument(char *ptr)
{
Chris Allegretta's avatar
Chris Allegretta committed
158
159
160
161
162
163
164
165
166
167
168
169
    const char *ptr_bak = ptr;
    char *last_quote = NULL;

    assert(ptr != NULL);

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

    do {
	ptr++;
	if (*ptr == '"')
	    last_quote = ptr;
170
    } while (*ptr != '\0');
Chris Allegretta's avatar
Chris Allegretta committed
171
172
173
174
175
176

    if (last_quote == NULL) {
	if (*ptr == '\0')
	    ptr = NULL;
	else
	    *ptr++ = '\0';
177
	rcfile_error(N_("Argument %s has unterminated \""), ptr_bak);
Chris Allegretta's avatar
Chris Allegretta committed
178
179
180
181
182
    } else {
	*last_quote = '\0';
	ptr = last_quote + 1;
    }
    if (ptr != NULL)
183
	while (is_blank_char(*ptr))
Chris Allegretta's avatar
Chris Allegretta committed
184
185
186
187
188
	    ptr++;
    return ptr;
}

#ifdef ENABLE_COLOR
189
int color_to_int(const char *colorname, bool *bright)
190
{
191
    int mcolor = -1;
192

193
194
    if (colorname == NULL) {
	rcfile_error(N_("Missing color name"));
195
	return -1;
196
197
198
    }

    assert(bright != NULL);
199

200
    if (strncasecmp(colorname, "bright", 6) == 0) {
201
	*bright = TRUE;
202
203
	colorname += 6;
    }
204

205
    if (strcasecmp(colorname, "green") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
206
	mcolor = COLOR_GREEN;
207
    else if (strcasecmp(colorname, "red") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
208
	mcolor = COLOR_RED;
209
    else if (strcasecmp(colorname, "blue") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
210
	mcolor = COLOR_BLUE;
211
    else if (strcasecmp(colorname, "white") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
212
	mcolor = COLOR_WHITE;
213
    else if (strcasecmp(colorname, "yellow") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
214
	mcolor = COLOR_YELLOW;
215
    else if (strcasecmp(colorname, "cyan") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
216
	mcolor = COLOR_CYAN;
217
    else if (strcasecmp(colorname, "magenta") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
218
	mcolor = COLOR_MAGENTA;
219
    else if (strcasecmp(colorname, "black") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
220
	mcolor = COLOR_BLACK;
221
    else
222
	rcfile_error(N_("Color %s not understood.\n"
223
224
225
		"Valid colors are \"green\", \"red\", \"blue\",\n"
		"\"white\", \"yellow\", \"cyan\", \"magenta\" and\n"
		"\"black\", with the optional prefix \"bright\"\n"
226
		"for foreground colors."), colorname);
227

228
229
230
    return mcolor;
}

231
232
char *parse_next_regex(char *ptr)
{
233
234
235
236
237
238
    assert(ptr != NULL);

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

241
242
243
    assert(*ptr == '"' || *ptr == '\0');

    if (*ptr == '\0') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
244
245
	rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
246
	return NULL;
247
    }
248

249
    /* Null terminate and advance ptr. */
250
251
    *ptr++ = '\0';

252
    while (is_blank_char(*ptr))
253
254
255
256
257
	ptr++;

    return ptr;
}

258
/* Compile the regular expression regex to preg.  Return FALSE on
259
 * success, or TRUE if the expression is invalid. */
260
bool nregcomp(regex_t *preg, const char *regex, int eflags)
261
{
262
    int rc = regcomp(preg, regex, REG_EXTENDED | eflags);
263
264
265
266
267
268

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

	regerror(rc, preg, str, len);
269
	rcfile_error(N_("Bad regex \"%s\": %s"), regex, str);
270
271
	free(str);
    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
272
273

    return (rc != 0);
274
275
}

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
276
void parse_syntax(char *ptr)
277
{
Chris Allegretta's avatar
Chris Allegretta committed
278
    const char *fileregptr = NULL, *nameptr = NULL;
279
280
    exttype *endext = NULL;
	/* The end of the extensions list for this syntax. */
281

282
    assert(ptr != NULL);
283

284
285
    if (*ptr == '\0') {
	rcfile_error(N_("Missing syntax name"));
286
	return;
287
    }
288
289

    if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
290
291
	rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
292
	return;
293
    }
294

295
296
297
298
299
    ptr++;

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

300
    if (ptr == NULL)
301
	return;
302

Chris Allegretta's avatar
Chris Allegretta committed
303
304
    if (syntaxes == NULL) {
	syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype));
305
	endsyntax = syntaxes;
Chris Allegretta's avatar
Chris Allegretta committed
306
    } else {
307
308
	endsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype));
	endsyntax = endsyntax->next;
309
#ifdef DEBUG
310
	fprintf(stderr, "Adding new syntax after first one\n");
311
#endif
Chris Allegretta's avatar
Chris Allegretta committed
312
    }
313
314
315
316
317
    endsyntax->desc = mallocstrcpy(NULL, nameptr);
    endsyntax->color = NULL;
    endcolor = NULL;
    endsyntax->extensions = NULL;
    endsyntax->next = NULL;
318
#ifdef DEBUG
319
    fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr);
320
321
#endif

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

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

330
	if (*ptr == '\0')
331
	    return;
332

333
334
335
336
	ptr++;

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);
337
338
	if (ptr == NULL)
	    break;
339

340
	newext = (exttype *)nmalloc(sizeof(exttype));
341
	if (nregcomp(&newext->val, fileregptr, REG_NOSUB))
342
343
344
	    free(newext);
	else {
	    if (endext == NULL)
345
		endsyntax->extensions = newext;
346
347
348
349
	    else
		endext->next = newext;
	    endext = newext;
	    endext->next = NULL;
350
	}
351
    }
352
353
}

354
/* Parse the color stuff into the colorstrings array. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
355
void parse_colors(char *ptr)
356
{
357
358
    int fg, bg;
    bool bright = FALSE;
Chris Allegretta's avatar
Chris Allegretta committed
359
    char *fgstr;
360

361
    assert(ptr != NULL);
362

363
    if (*ptr == '\0') {
364
	rcfile_error(N_("Missing color name"));
365
	return;
366
367
    }

368
369
370
371
    fgstr = ptr;
    ptr = parse_next_word(ptr);

    if (strchr(fgstr, ',') != NULL) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
372
	char *bgcolorname;
373
	strtok(fgstr, ",");
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
374
	bgcolorname = strtok(NULL, ",");
375
	if (strncasecmp(bgcolorname, "bright", 6) == 0) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
376
377
378
	    rcfile_error(
		N_("Background color %s cannot be bright"),
		bgcolorname);
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
379
380
	    return;
	}
381
	bg = color_to_int(bgcolorname, &bright);
382
    } else
Chris Allegretta's avatar
Chris Allegretta committed
383
	bg = -1;
384

385
    fg = color_to_int(fgstr, &bright);
386

387
    /* Don't try to parse screwed-up foreground colors. */
388
389
390
    if (fg == -1)
	return;

391
    if (syntaxes == NULL) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
392
393
	rcfile_error(
		N_("Cannot add a color directive without a syntax line"));
394
	return;
395
396
    }

397
398
    /* Now for the fun part.  Start adding regexps to individual strings
     * in the colorstrings array, woo! */
399

400
    while (ptr != NULL && *ptr != '\0') {
401
402
	colortype *newcolor;
	    /* The new color structure. */
403
	bool cancelled = FALSE;
404
	    /* The start expression was bad. */
405
406
	bool expectend = FALSE;
	    /* Do we expect an end= line? */
407

408
	if (strncasecmp(ptr, "start=", 6) == 0) {
409
	    ptr += 6;
410
	    expectend = TRUE;
411
412
413
	}

	if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
414
415
	    rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
416
	    ptr = parse_next_regex(ptr);
417
418
	    continue;
	}
419

420
	ptr++;
421

422
423
424
	newcolor = (colortype *)nmalloc(sizeof(colortype));
	fgstr = ptr;
	ptr = parse_next_regex(ptr);
425
426
427
428
	if (ptr == NULL)
	    break;

	if (nregcomp(&newcolor->start, fgstr, 0)) {
429
	    free(newcolor);
430
	    cancelled = TRUE;
431
	} else {
432
433
434
435
436
437
	    newcolor->fg = fg;
	    newcolor->bg = bg;
	    newcolor->bright = bright;
	    newcolor->next = NULL;
	    newcolor->end = NULL;

438
439
	    if (endcolor == NULL) {
		endsyntax->color = newcolor;
440
#ifdef DEBUG
441
		fprintf(stderr, "Starting a new colorstring for fg %d, bg %d\n", fg, bg);
442
#endif
443
	    } else {
Chris Allegretta's avatar
Chris Allegretta committed
444
#ifdef DEBUG
445
		fprintf(stderr, "Adding new entry for fg %d, bg %d\n", fg, bg);
Chris Allegretta's avatar
Chris Allegretta committed
446
#endif
447
		endcolor->next = newcolor;
448
	    }
449
	    endcolor = newcolor;
450
	}
Chris Allegretta's avatar
Chris Allegretta committed
451

452
	if (expectend) {
453
	    if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
454
455
		rcfile_error(
			N_("\"start=\" requires a corresponding \"end=\""));
456
457
458
459
		return;
	    }
	    ptr += 4;
	    if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
460
461
		rcfile_error(
			N_("Regex strings must begin and end with a \" character"));
462
		continue;
463
	    }
464

465
466
	    ptr++;

467
	    fgstr = ptr;
468
	    ptr = parse_next_regex(ptr);
469
470
	    if (ptr == NULL)
		break;
471
472
473
474
475

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

477
	    newcolor->end = (regex_t *)nmalloc(sizeof(regex_t));
478
	    if (nregcomp(newcolor->end, fgstr, 0)) {
479
480
481
		free(newcolor->end);
		newcolor->end = NULL;
	    }
Chris Allegretta's avatar
Chris Allegretta committed
482
	}
483
    }
484
}
485
#endif /* ENABLE_COLOR */
486

487
/* Parse the rcfile, once it has been opened successfully. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
488
void parse_rcfile(FILE *rcstream)
489
{
490
491
492
493
494
495
496
497
498
499
    char *buf = NULL;
    ssize_t len;
    size_t n;

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

	/* Ignore the \n. */
	buf[len - 1] = '\0';
500
501
502

	lineno++;
	ptr = buf;
503
	while (is_blank_char(*ptr))
504
505
	    ptr++;

506
507
508
	/* If we have a blank line or a comment, skip to the next
	 * line. */
	if (*ptr == '\0' || *ptr == '#')
509
510
	    continue;

511
	/* Otherwise, skip to the next space. */
512
513
514
	keyword = ptr;
	ptr = parse_next_word(ptr);

515
	/* Try to parse the keyword. */
516
	if (strcasecmp(keyword, "set") == 0)
517
	    set = 1;
518
	else if (strcasecmp(keyword, "unset") == 0)
519
	    set = -1;
520
#ifdef ENABLE_COLOR
521
	else if (strcasecmp(keyword, "syntax") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
522
	    parse_syntax(ptr);
523
	else if (strcasecmp(keyword, "color") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
524
	    parse_colors(ptr);
525
526
#endif /* ENABLE_COLOR */
	else
527
	    rcfile_error(N_("Command %s not understood"), keyword);
528
529
530
531
532
533

	if (set == 0)
	    continue;

	if (*ptr == '\0') {
	    rcfile_error(N_("Missing flag"));
534
535
536
537
538
539
	    continue;
	}

	option = ptr;
	ptr = parse_next_word(ptr);

540
541
	for (i = 0; rcopts[i].name != NULL; i++) {
	    if (strcasecmp(option, rcopts[i].name) == 0) {
542
#ifdef DEBUG
543
544
545
546
547
548
549
550
551
552
553
		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
			 *an argument. */
			if (*ptr == '\0') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
554
555
556
			    rcfile_error(
				N_("Option %s requires an argument"),
				rcopts[i].name);
557
558
559
560
561
562
			    break;
			}
			option = ptr;
			if (*option == '"')
			    option++;
			ptr = parse_argument(ptr);
563
			option = make_mbstring(option);
Chris Allegretta's avatar
Chris Allegretta committed
564
#ifdef DEBUG
565
			fprintf(stderr, "option = \"%s\"\n", option);
Chris Allegretta's avatar
Chris Allegretta committed
566
567
#endif
#ifndef DISABLE_OPERATINGDIR
568
			if (strcasecmp(rcopts[i].name, "operatingdir") == 0)
569
			    operating_dir = option;
570
			else
Chris Allegretta's avatar
Chris Allegretta committed
571
#endif
572
#ifndef DISABLE_WRAPJUSTIFY
573
574
			if (strcasecmp(rcopts[i].name, "fill") == 0) {
			    if (!parse_num(option, &wrap_at)) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
575
576
577
				rcfile_error(
					N_("Requested fill size %s invalid"),
					option);
578
				wrap_at = -CHARS_FROM_EOL;
579
580
			    } else
				free(option);
581
			} else
Chris Allegretta's avatar
Chris Allegretta committed
582
#endif
583
#ifndef NANO_SMALL
584
			if (strcasecmp(rcopts[i].name, "whitespace") == 0) {
585
			    whitespace = option;
586
			    if (mbstrlen(whitespace) != 2 || strlenpt(whitespace) != 2) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
587
588
				rcfile_error(
					N_("Two single-column characters required"));
589
590
				free(whitespace);
				whitespace = NULL;
591
592
593
594
595
596
597
598
			    } else {
				whitespace_len[0] =
					parse_mbchar(whitespace, NULL,
					NULL, NULL);
				whitespace_len[1] =
					parse_mbchar(whitespace +
					whitespace_len[0], NULL,
					NULL, NULL);
599
600
			    }
			} else
601
#endif
602
#ifndef DISABLE_JUSTIFY
603
			if (strcasecmp(rcopts[i].name, "punct") == 0) {
604
			    punct = option;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
605
606
607
608
			    if (strchr(punct, '\t') != NULL ||
				strchr(punct, ' ') != NULL) {
				rcfile_error(
					N_("Non-tab and non-space characters required"));
609
610
611
				free(punct);
				punct = NULL;
			    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
612
613
			} else if (strcasecmp(rcopts[i].name,
				"brackets") == 0) {
614
			    brackets = option;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
615
616
617
618
			    if (strchr(brackets, '\t') != NULL ||
				strchr(brackets, ' ') != NULL) {
				rcfile_error(
					N_("Non-tab and non-space characters required"));
619
620
621
				free(brackets);
				brackets = NULL;
			    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
622
623
			} else if (strcasecmp(rcopts[i].name,
				"quotestr") == 0)
624
			    quotestr = option;
625
			else
626
#endif
627
#ifndef NANO_SMALL
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
628
629
			if (strcasecmp(rcopts[i].name,
				"backupdir") == 0)
630
			    backup_dir = option;
631
			else
632
#endif
633
#ifndef DISABLE_SPELLER
634
			if (strcasecmp(rcopts[i].name, "speller") == 0)
635
			    alt_speller = option;
636
637
			else
#endif
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
638
639
640
641
642
643
644
			if (strcasecmp(rcopts[i].name,
				"tabsize") == 0) {
			    if (!parse_num(option, &tabsize) ||
				tabsize <= 0) {
				rcfile_error(
					N_("Requested tab size %s invalid"),
					option);
645
				tabsize = -1;
646
647
			    } else
				free(option);
648
			} else
649
650
			    assert(FALSE);
		    }
651
#ifdef DEBUG
652
		    fprintf(stderr, "flag = %ld\n", rcopts[i].flag);
653
#endif
654
655
656
		} else if (rcopts[i].flag != 0)
		    UNSET(rcopts[i].flag);
		else
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
657
658
		    rcfile_error(N_("Cannot unset flag %s"),
			rcopts[i].name);
659
		break;
660
661
	    }
	}
662
663
	if (rcopts[i].name == NULL)
	    rcfile_error(N_("Unknown flag %s"), option);
664
    }
665

Chris Allegretta's avatar
Chris Allegretta committed
666
    free(buf);
667
668
    fclose(rcstream);
    lineno = 0;
669
670
671

    if (errors) {
	errors = FALSE;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
672
673
	fprintf(stderr,
		_("\nPress Return to continue starting nano\n"));
674
675
676
677
	while (getchar() != '\n')
	    ;
    }

678
679
680
681
682
683
684
685
    return;
}

/* The main rc file function, tries to open the rc file */
void do_rcfile(void)
{
    FILE *rcstream;

Chris Allegretta's avatar
Chris Allegretta committed
686
687
#ifdef SYSCONFDIR
    assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
688

689
690
    nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");
    /* Try to open the system-wide nanorc. */
691
    rcstream = fopen(nanorc, "r");
692
    if (rcstream != NULL)
Chris Allegretta's avatar
Chris Allegretta committed
693
694
	parse_rcfile(rcstream);
#endif
695

696
697
698
699
700
701
702
#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
    /* We've already read SYSCONFDIR/nanorc, if it's there.  If we're
     * root and --disable-wrapping-as-root is used, turn wrapping
     * off now. */
    if (geteuid() == NANO_ROOT_UID)
	SET(NO_WRAP);
#endif
Chris Allegretta's avatar
Chris Allegretta committed
703

704
    get_homedir();
705

706
    if (homedir == NULL)
707
	rcfile_error(N_("I can't find my home directory!  Wah!"));
708
709
710
    else {
	nanorc = charealloc(nanorc, strlen(homedir) + 9);
	sprintf(nanorc, "%s/.nanorc", homedir);
711
	rcstream = fopen(nanorc, "r");
712

713
	if (rcstream == NULL) {
714
715
	    /* Don't complain about the file's not existing. */
	    if (errno != ENOENT)
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
716
717
		rcfile_error(N_("Error reading %s: %s"), nanorc,
			strerror(errno));
718
	} else
Chris Allegretta's avatar
Chris Allegretta committed
719
	    parse_rcfile(rcstream);
720
    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
721

722
723
    free(nanorc);
    nanorc = NULL;
724

725
726
727
#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
728
729
}

730
#endif /* ENABLE_NANORC */