rcfile.c 17.4 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
 *   any later version.                                                   *
 *                                                                        *
11
12
13
14
 *   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.                             *
15
16
17
 *                                                                        *
 *   You should have received a copy of the GNU General Public License    *
 *   along with this program; if not, write to the Free Software          *
18
19
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA            *
 *   02110-1301, USA.                                                     *
20
21
22
 *                                                                        *
 **************************************************************************/

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

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

#ifdef ENABLE_NANORC

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

99
static bool errors = FALSE;
100
static int lineno = 0;
101
102
103
104
105
106
107
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
108

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

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

121
    va_start(ap, msg);
122
    vfprintf(stderr, _(msg), ap);
123
    va_end(ap);
124
125

    fprintf(stderr, "\n");
126
127
}

128
129
/* 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
130
char *parse_next_word(char *ptr)
131
{
132
    while (!is_blank_char(*ptr) && *ptr != '\0')
133
134
135
	ptr++;

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

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

141
    while (is_blank_char(*ptr))
142
143
144
145
	ptr++;

    return ptr;
}
146

147
148
149
150
151
152
153
/* 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
154
155
char *parse_argument(char *ptr)
{
Chris Allegretta's avatar
Chris Allegretta committed
156
157
158
159
160
161
162
163
164
165
166
167
    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;
168
    } while (*ptr != '\0');
Chris Allegretta's avatar
Chris Allegretta committed
169
170
171
172
173
174

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

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

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

    assert(bright != NULL);
197

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

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

226
227
228
    return mcolor;
}

229
230
char *parse_next_regex(char *ptr)
{
231
232
233
234
235
236
    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')
237
238
	ptr++;

239
240
241
    assert(*ptr == '"' || *ptr == '\0');

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

247
    /* Null terminate and advance ptr. */
248
249
    *ptr++ = '\0';

250
    while (is_blank_char(*ptr))
251
252
253
254
255
	ptr++;

    return ptr;
}

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

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

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

    return (rc != 0);
272
273
}

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

280
    assert(ptr != NULL);
281

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

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

293
294
295
296
297
    ptr++;

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

298
    if (ptr == NULL)
299
	return;
300

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

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

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

328
	if (*ptr == '\0')
329
	    return;
330

331
332
333
334
	ptr++;

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);
335
336
	if (ptr == NULL)
	    break;
337

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

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

359
    assert(ptr != NULL);
360

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

366
367
368
369
    fgstr = ptr;
    ptr = parse_next_word(ptr);

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

372
	strtok(fgstr, ",");
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
373
	bgcolorname = strtok(NULL, ",");
374
375
376
377
378
379
	if (bgcolorname == NULL) {
	    /* If we have a background color without a foreground color,
	     * parse it properly. */
	    bgcolorname = fgstr + 1;
	    no_fgcolor = TRUE;
	}
380
	if (strncasecmp(bgcolorname, "bright", 6) == 0) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
381
382
383
	    rcfile_error(
		N_("Background color %s cannot be bright"),
		bgcolorname);
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
384
385
	    return;
	}
386
	bg = color_to_int(bgcolorname, &bright);
387
    } else
Chris Allegretta's avatar
Chris Allegretta committed
388
	bg = -1;
389

390
391
    if (!no_fgcolor) {
	fg = color_to_int(fgstr, &bright);
392

393
394
395
396
397
	/* Don't try to parse screwed-up foreground colors. */
	if (fg == -1)
	    return;
    } else
	fg = -1;
398

399
    if (syntaxes == NULL) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
400
401
	rcfile_error(
		N_("Cannot add a color directive without a syntax line"));
402
	return;
403
404
    }

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
405
    /* Now for the fun part.  Start adding regexes to individual strings
406
407
     * in the colorstrings array, woo! */
    while (ptr != NULL && *ptr != '\0') {
408
409
	colortype *newcolor;
	    /* The new color structure. */
410
	bool cancelled = FALSE;
411
	    /* The start expression was bad. */
412
413
	bool expectend = FALSE;
	    /* Do we expect an end= line? */
414

415
	if (strncasecmp(ptr, "start=", 6) == 0) {
416
	    ptr += 6;
417
	    expectend = TRUE;
418
419
420
	}

	if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
421
422
	    rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
423
	    ptr = parse_next_regex(ptr);
424
425
	    continue;
	}
426

427
	ptr++;
428

429
430
431
	newcolor = (colortype *)nmalloc(sizeof(colortype));
	fgstr = ptr;
	ptr = parse_next_regex(ptr);
432
433
434
435
	if (ptr == NULL)
	    break;

	if (nregcomp(&newcolor->start, fgstr, 0)) {
436
	    free(newcolor);
437
	    cancelled = TRUE;
438
	} else {
439
440
441
442
443
444
	    newcolor->fg = fg;
	    newcolor->bg = bg;
	    newcolor->bright = bright;
	    newcolor->next = NULL;
	    newcolor->end = NULL;

445
446
	    if (endcolor == NULL) {
		endsyntax->color = newcolor;
447
#ifdef DEBUG
448
		fprintf(stderr, "Starting a new colorstring for fg %d, bg %d\n", fg, bg);
449
#endif
450
	    } else {
Chris Allegretta's avatar
Chris Allegretta committed
451
#ifdef DEBUG
452
		fprintf(stderr, "Adding new entry for fg %d, bg %d\n", fg, bg);
Chris Allegretta's avatar
Chris Allegretta committed
453
#endif
454
		endcolor->next = newcolor;
455
	    }
456
	    endcolor = newcolor;
457
	}
Chris Allegretta's avatar
Chris Allegretta committed
458

459
	if (expectend) {
460
	    if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
461
462
		rcfile_error(
			N_("\"start=\" requires a corresponding \"end=\""));
463
464
465
466
		return;
	    }
	    ptr += 4;
	    if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
467
468
		rcfile_error(
			N_("Regex strings must begin and end with a \" character"));
469
		continue;
470
	    }
471

472
473
	    ptr++;

474
	    fgstr = ptr;
475
	    ptr = parse_next_regex(ptr);
476
477
	    if (ptr == NULL)
		break;
478
479
480
481
482

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

484
	    newcolor->end = (regex_t *)nmalloc(sizeof(regex_t));
485
	    if (nregcomp(newcolor->end, fgstr, 0)) {
486
487
488
		free(newcolor->end);
		newcolor->end = NULL;
	    }
Chris Allegretta's avatar
Chris Allegretta committed
489
	}
490
    }
491
}
492
#endif /* ENABLE_COLOR */
493

494
/* Parse the rcfile, once it has been opened successfully. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
495
void parse_rcfile(FILE *rcstream)
496
{
497
498
499
500
501
502
503
504
505
506
    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';
507
508
509

	lineno++;
	ptr = buf;
510
	while (is_blank_char(*ptr))
511
512
	    ptr++;

513
514
515
	/* If we have a blank line or a comment, skip to the next
	 * line. */
	if (*ptr == '\0' || *ptr == '#')
516
517
	    continue;

518
	/* Otherwise, skip to the next space. */
519
520
521
	keyword = ptr;
	ptr = parse_next_word(ptr);

522
	/* Try to parse the keyword. */
523
	if (strcasecmp(keyword, "set") == 0)
524
	    set = 1;
525
	else if (strcasecmp(keyword, "unset") == 0)
526
	    set = -1;
527
#ifdef ENABLE_COLOR
528
	else if (strcasecmp(keyword, "syntax") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
529
	    parse_syntax(ptr);
530
	else if (strcasecmp(keyword, "color") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
531
	    parse_colors(ptr);
532
533
#endif /* ENABLE_COLOR */
	else
534
	    rcfile_error(N_("Command %s not understood"), keyword);
535
536
537
538
539
540

	if (set == 0)
	    continue;

	if (*ptr == '\0') {
	    rcfile_error(N_("Missing flag"));
541
542
543
544
545
546
	    continue;
	}

	option = ptr;
	ptr = parse_next_word(ptr);

547
548
	for (i = 0; rcopts[i].name != NULL; i++) {
	    if (strcasecmp(option, rcopts[i].name) == 0) {
549
#ifdef DEBUG
550
551
552
553
554
555
556
557
558
559
560
		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
561
562
563
			    rcfile_error(
				N_("Option %s requires an argument"),
				rcopts[i].name);
564
565
566
567
568
569
			    break;
			}
			option = ptr;
			if (*option == '"')
			    option++;
			ptr = parse_argument(ptr);
570
571
572

			/* Make sure option is a valid multibyte
			 * string. */
573
			option = make_mbstring(option);
Chris Allegretta's avatar
Chris Allegretta committed
574
#ifdef DEBUG
575
			fprintf(stderr, "option = \"%s\"\n", option);
Chris Allegretta's avatar
Chris Allegretta committed
576
577
#endif
#ifndef DISABLE_OPERATINGDIR
578
			if (strcasecmp(rcopts[i].name, "operatingdir") == 0)
579
			    operating_dir = option;
580
			else
Chris Allegretta's avatar
Chris Allegretta committed
581
#endif
582
#ifndef DISABLE_WRAPJUSTIFY
583
584
			if (strcasecmp(rcopts[i].name, "fill") == 0) {
			    if (!parse_num(option, &wrap_at)) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
585
586
587
				rcfile_error(
					N_("Requested fill size %s invalid"),
					option);
588
				wrap_at = -CHARS_FROM_EOL;
589
590
			    } else
				free(option);
591
			} else
Chris Allegretta's avatar
Chris Allegretta committed
592
#endif
593
#ifndef NANO_SMALL
594
			if (strcasecmp(rcopts[i].name, "whitespace") == 0) {
595
			    whitespace = option;
596
			    if (mbstrlen(whitespace) != 2 || strlenpt(whitespace) != 2) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
597
598
				rcfile_error(
					N_("Two single-column characters required"));
599
600
				free(whitespace);
				whitespace = NULL;
601
602
603
604
605
606
607
608
			    } else {
				whitespace_len[0] =
					parse_mbchar(whitespace, NULL,
					NULL, NULL);
				whitespace_len[1] =
					parse_mbchar(whitespace +
					whitespace_len[0], NULL,
					NULL, NULL);
609
610
			    }
			} else
611
#endif
612
#ifndef DISABLE_JUSTIFY
613
			if (strcasecmp(rcopts[i].name, "punct") == 0) {
614
			    punct = option;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
615
616
617
618
			    if (strchr(punct, '\t') != NULL ||
				strchr(punct, ' ') != NULL) {
				rcfile_error(
					N_("Non-tab and non-space characters required"));
619
620
621
				free(punct);
				punct = NULL;
			    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
622
623
			} else if (strcasecmp(rcopts[i].name,
				"brackets") == 0) {
624
			    brackets = option;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
625
626
627
628
			    if (strchr(brackets, '\t') != NULL ||
				strchr(brackets, ' ') != NULL) {
				rcfile_error(
					N_("Non-tab and non-space characters required"));
629
630
631
				free(brackets);
				brackets = NULL;
			    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
632
633
			} else if (strcasecmp(rcopts[i].name,
				"quotestr") == 0)
634
			    quotestr = option;
635
			else
636
#endif
637
#ifndef NANO_SMALL
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
638
639
			if (strcasecmp(rcopts[i].name,
				"backupdir") == 0)
640
			    backup_dir = option;
641
			else
642
#endif
643
#ifndef DISABLE_SPELLER
644
			if (strcasecmp(rcopts[i].name, "speller") == 0)
645
			    alt_speller = option;
646
647
			else
#endif
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
648
649
650
651
652
653
654
			if (strcasecmp(rcopts[i].name,
				"tabsize") == 0) {
			    if (!parse_num(option, &tabsize) ||
				tabsize <= 0) {
				rcfile_error(
					N_("Requested tab size %s invalid"),
					option);
655
				tabsize = -1;
656
657
			    } else
				free(option);
658
			} else
659
660
			    assert(FALSE);
		    }
661
#ifdef DEBUG
662
		    fprintf(stderr, "flag = %ld\n", rcopts[i].flag);
663
#endif
664
665
666
		} else if (rcopts[i].flag != 0)
		    UNSET(rcopts[i].flag);
		else
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
667
668
		    rcfile_error(N_("Cannot unset flag %s"),
			rcopts[i].name);
669
		break;
670
671
	    }
	}
672
673
	if (rcopts[i].name == NULL)
	    rcfile_error(N_("Unknown flag %s"), option);
674
    }
675

Chris Allegretta's avatar
Chris Allegretta committed
676
    free(buf);
677
678
    fclose(rcstream);
    lineno = 0;
679
680
681

    if (errors) {
	errors = FALSE;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
682
683
	fprintf(stderr,
		_("\nPress Return to continue starting nano\n"));
684
685
686
687
	while (getchar() != '\n')
	    ;
    }

688
689
690
691
692
693
694
695
    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
696
697
#ifdef SYSCONFDIR
    assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
698

699
700
    nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");
    /* Try to open the system-wide nanorc. */
701
    rcstream = fopen(nanorc, "r");
702
    if (rcstream != NULL)
Chris Allegretta's avatar
Chris Allegretta committed
703
704
	parse_rcfile(rcstream);
#endif
705

706
707
708
709
710
711
712
#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
713

714
    get_homedir();
715

716
    if (homedir == NULL)
717
	rcfile_error(N_("I can't find my home directory!  Wah!"));
718
719
720
    else {
	nanorc = charealloc(nanorc, strlen(homedir) + 9);
	sprintf(nanorc, "%s/.nanorc", homedir);
721
	rcstream = fopen(nanorc, "r");
722

723
	if (rcstream == NULL) {
724
725
	    /* Don't complain about the file's not existing. */
	    if (errno != ENOENT)
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
726
727
		rcfile_error(N_("Error reading %s: %s"), nanorc,
			strerror(errno));
728
	} else
Chris Allegretta's avatar
Chris Allegretta committed
729
	    parse_rcfile(rcstream);
730
    }
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
731

732
733
    free(nanorc);
    nanorc = NULL;
734

735
736
737
#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
738
739
}

740
#endif /* ENABLE_NANORC */