rcfile.c 17.7 KB
Newer Older
1
2
/* $Id$ */
/**************************************************************************
3
 *   rcfile.c                                                             *
4
 *                                                                        *
5
 *   Copyright (C) 1999-2004 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 <fcntl.h>
Chris Allegretta's avatar
Chris Allegretta committed
33
#include <pwd.h>
34
#include <ctype.h>
Chris Allegretta's avatar
Chris Allegretta committed
35
#include <assert.h>
36
37
38
39
40
#include "proto.h"
#include "nano.h"

#ifdef ENABLE_NANORC

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

103
static bool errors = FALSE;
104
static int lineno = 0;
105
static const char *nanorc;
106

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

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

119
    va_start(ap, msg);
120
    vfprintf(stderr, _(msg), ap);
121
    va_end(ap);
122
123

    fprintf(stderr, "\n");
124
125
}

Chris Allegretta's avatar
Chris Allegretta committed
126
/* Parse the next word from the string.  Returns NULL if we hit EOL. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
127
char *parse_next_word(char *ptr)
128
{
129
    while (!is_blank_char(*ptr) && *ptr != '\n' && *ptr != '\0')
130
131
132
133
134
135
136
137
	ptr++;

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

    /* Null terminate and advance ptr */
    *ptr++ = 0;

138
    while (is_blank_char(*ptr))
139
140
141
142
	ptr++;

    return ptr;
}
143

144
/* The keywords operatingdir, backupdir, fill, tabsize, speller,
145
146
147
148
149
150
 * 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
151
152
char *parse_argument(char *ptr)
{
Chris Allegretta's avatar
Chris Allegretta committed
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    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;
    } while (*ptr != '\n' && *ptr != '\0');

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

#ifdef ENABLE_COLOR

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
185
int colortoint(const char *colorname, int *bright)
186
187
188
189
190
191
{
    int mcolor = 0;

    if (colorname == NULL)
	return -1;

192
    if (strncasecmp(colorname, "bright", 6) == 0) {
193
	*bright = 1;
194
195
	colorname += 6;
    }
196

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

224
225
226
227
228
229
230
231
232
char *parse_next_regex(char *ptr)
{
    while ((*ptr != '"' || (*(ptr + 1) != ' ' && *(ptr + 1) != '\n'))
	   && *ptr != '\n' && *ptr != '\0')
	ptr++;

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

233
    /* Null terminate and advance ptr. */
234
235
    *ptr++ = '\0';

236
    while (is_blank_char(*ptr))
237
238
239
240
241
	ptr++;

    return ptr;
}

242
243
244
/* Compile the regular expression regex to preg.  Returns FALSE on
 * success, or TRUE if the expression is invalid. */
int nregcomp(regex_t *preg, const char *regex, int eflags)
245
{
246
    int rc = regcomp(preg, regex, REG_EXTENDED | eflags);
247
248
249
250
251
252

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

	regerror(rc, preg, str, len);
253
	rcfile_error(N_("Bad regex \"%s\": %s"), regex, str);
254
255
256
257
258
	free(str);
    }
    return rc != 0;
}

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
259
void parse_syntax(char *ptr)
260
261
{
    syntaxtype *tmpsyntax = NULL;
Chris Allegretta's avatar
Chris Allegretta committed
262
    const char *fileregptr = NULL, *nameptr = NULL;
263
264
    exttype *endext = NULL;
	/* The end of the extensions list for this syntax. */
265
266
267
268
269
270
271
272

    while (*ptr == ' ')
	ptr++;

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

    if (*ptr != '"') {
273
	rcfile_error(N_("Regex strings must begin and end with a \" character"));
274
	return;
275
276
277
278
279
280
281
    }
    ptr++;

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

    if (ptr == NULL) {
282
	rcfile_error(N_("Missing syntax name"));
283
	return;
284
285
    }

Chris Allegretta's avatar
Chris Allegretta committed
286
287
288
    if (syntaxes == NULL) {
	syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype));
	tmpsyntax = syntaxes;
289
	SET(COLOR_SYNTAX);
Chris Allegretta's avatar
Chris Allegretta committed
290
291
292
293
294
295
    } else {
	for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
		tmpsyntax = tmpsyntax->next)
	    ;
	tmpsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype));
	tmpsyntax = tmpsyntax->next;
296
#ifdef DEBUG
297
	fprintf(stderr, "Adding new syntax after 1st\n");
298
#endif
Chris Allegretta's avatar
Chris Allegretta committed
299
300
301
302
303
    }
    tmpsyntax->desc = mallocstrcpy(NULL, nameptr);
    tmpsyntax->color = NULL;
    tmpsyntax->extensions = NULL;
    tmpsyntax->next = NULL;
304
#ifdef DEBUG
305
    fprintf(stderr, "Starting a new syntax type\n");
Chris Allegretta's avatar
Chris Allegretta committed
306
    fprintf(stderr, "string val=%s\n", nameptr);
307
308
309
310
#endif

    /* Now load in the extensions to their part of the struct */
    while (*ptr != '\n' && *ptr != '\0') {
311
312
313
	exttype *newext;
	    /* The new extension structure. */

314
315
316
317
318
319
320
321
322
323
	while (*ptr != '"' && *ptr != '\n' && *ptr != '\0')
	    ptr++;

	if (*ptr == '\n' || *ptr == '\0')
	    return;
	ptr++;

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);

324
	newext = (exttype *)nmalloc(sizeof(exttype));
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
325
	if (nregcomp(&newext->val, fileregptr, REG_NOSUB) != 0)
326
327
328
329
330
331
332
333
	    free(newext);
	else {
	    if (endext == NULL)
		tmpsyntax->extensions = newext;
	    else
		endext->next = newext;
	    endext = newext;
	    endext->next = NULL;
334
	}
335
    }
336
337
}

338
/* Parse the color stuff into the colorstrings array */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
339
void parse_colors(char *ptr)
340
{
341
342
    int fg, bg, bright = 0;
    int expectend = 0;		/* Do we expect an end= line? */
Chris Allegretta's avatar
Chris Allegretta committed
343
    char *fgstr;
344
    colortype *tmpcolor = NULL;
345
    syntaxtype *tmpsyntax = NULL;
346
347
348
349
350

    fgstr = ptr;
    ptr = parse_next_word(ptr);

    if (ptr == NULL) {
351
	rcfile_error(N_("Missing color name"));
352
	return;
353
354
355
    }

    if (strstr(fgstr, ",")) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
356
	char *bgcolorname;
357
	strtok(fgstr, ",");
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
358
	bgcolorname = strtok(NULL, ",");
359
	if (strncasecmp(bgcolorname, "bright", 6) == 0) {
360
	    rcfile_error(N_("Background color %s cannot be bright"), bgcolorname);
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
361
362
363
	    return;
	}
	bg = colortoint(bgcolorname, &bright);
364
    } else
Chris Allegretta's avatar
Chris Allegretta committed
365
	bg = -1;
366

367
    fg = colortoint(fgstr, &bright);
368

369
370
371
372
    /* Don't try and parse screwed up fg colors */
    if (fg == -1)
	return;

373
    if (syntaxes == NULL) {
374
	rcfile_error(N_("Cannot add a color directive without a syntax line"));
375
	return;
376
377
378
379
380
381
    }

    for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
	 tmpsyntax = tmpsyntax->next)
	;

382
    /* Now the fun part, start adding regexps to individual strings
383
       in the colorstrings array, woo! */
384

385
    while (*ptr != '\0') {
386
387
388
389
390
	colortype *newcolor;
	    /* The new color structure. */
	int cancelled = 0;
	    /* The start expression was bad. */

391
392
393
394
395
396
	while (*ptr == ' ')
	    ptr++;

	if (*ptr == '\n' || *ptr == '\0')
	    break;

397
	if (strncasecmp(ptr, "start=", 6) == 0) {
398
399
400
401
402
	    ptr += 6;
	    expectend = 1;
	}

	if (*ptr != '"') {
403
	    rcfile_error(N_("Regex strings must begin and end with a \" character"));
404
	    ptr = parse_next_regex(ptr);
405
406
407
	    continue;
	}
	ptr++;
408

409
410
411
	newcolor = (colortype *)nmalloc(sizeof(colortype));
	fgstr = ptr;
	ptr = parse_next_regex(ptr);
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
412
	if (nregcomp(&newcolor->start, fgstr, 0) != 0) {
413
414
	    free(newcolor);
	    cancelled = 1;
415
	} else {
416
417
418
419
420
421
422
423
	    newcolor->fg = fg;
	    newcolor->bg = bg;
	    newcolor->bright = bright;
	    newcolor->next = NULL;
	    newcolor->end = NULL;

	    if (tmpsyntax->color == NULL) {
		tmpsyntax->color = newcolor;
424
#ifdef DEBUG
425
		fprintf(stderr, "Starting a new colorstring for fg %d bg %d\n", fg, bg);
426
#endif
427
428
429
430
	    } else {
		for (tmpcolor = tmpsyntax->color; tmpcolor->next != NULL;
			tmpcolor = tmpcolor->next)
		    ;
Chris Allegretta's avatar
Chris Allegretta committed
431
#ifdef DEBUG
432
		fprintf(stderr, "Adding new entry for fg %d bg %d\n", fg, bg);
Chris Allegretta's avatar
Chris Allegretta committed
433
#endif
434
435
436
		tmpcolor->next = newcolor;
	    }
	}
Chris Allegretta's avatar
Chris Allegretta committed
437

438
	if (expectend) {
439
	    if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) {
440
		rcfile_error(N_("\"start=\" requires a corresponding \"end=\""));
441
442
		return;
	    }
443

444
	    ptr += 4;
445

446
	    if (*ptr != '"') {
447
		rcfile_error(N_("Regex strings must begin and end with a \" character"));
448
		continue;
449
450
451
	    }
	    ptr++;

452
	    fgstr = ptr;
453
	    ptr = parse_next_regex(ptr);
454
455
456
457
458
459

	    /* If the start regex was invalid, skip past the end regex to
	     * stay in sync. */
	    if (cancelled)
		continue;
	    newcolor->end = (regex_t *)nmalloc(sizeof(regex_t));
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
460
	    if (nregcomp(newcolor->end, fgstr, 0) != 0) {
461
462
463
		free(newcolor->end);
		newcolor->end = NULL;
	    }
Chris Allegretta's avatar
Chris Allegretta committed
464
	}
465
    }
466
}
467
468

#endif /* ENABLE_COLOR */
469

470
/* Parse the RC file, once it has been opened successfully */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
471
void parse_rcfile(FILE *rcstream)
472
473
{
    char *buf, *ptr, *keyword, *option;
474
    int set = 0, i;
475

476
    buf = charalloc(1024);
Chris Allegretta's avatar
Chris Allegretta committed
477
    while (fgets(buf, 1023, rcstream) != 0) {
478
479
	lineno++;
	ptr = buf;
480
	while (is_blank_char(*ptr))
481
482
483
484
485
486
487
	    ptr++;

	if (*ptr == '\n' || *ptr == '\0')
	    continue;

	if (*ptr == '#') {
#ifdef DEBUG
488
	    fprintf(stderr, "%s: Read a comment\n", "parse_rcfile()");
489
#endif
490
	    continue;		/* Skip past commented lines */
491
492
493
494
495
	}

	/* Else skip to the next space */
	keyword = ptr;
	ptr = parse_next_word(ptr);
496
	if (ptr == NULL)
497
498
499
	    continue;

	/* Else try to parse the keyword */
500
	if (strcasecmp(keyword, "set") == 0)
501
	    set = 1;
502
	else if (strcasecmp(keyword, "unset") == 0)
503
	    set = -1;
504
#ifdef ENABLE_COLOR
505
	else if (strcasecmp(keyword, "syntax") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
506
	    parse_syntax(ptr);
507
	else if (strcasecmp(keyword, "color") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
508
	    parse_colors(ptr);
509
#endif				/* ENABLE_COLOR */
510
	else {
511
	    rcfile_error(N_("Command %s not understood"), keyword);
512
513
514
515
516
517
518
519
	    continue;
	}

	option = ptr;
	ptr = parse_next_word(ptr);
	/* We don't care if ptr == NULL, as it should if using proper syntax */

	if (set != 0) {
520
	    for (i = 0; rcopts[i].name != NULL; i++) {
521
		if (strcasecmp(option, rcopts[i].name) == 0) {
522
#ifdef DEBUG
523
		    fprintf(stderr, "%s: Parsing option %s\n", 
524
			    "parse_rcfile()", rcopts[i].name);
525
#endif
526
		    if (set == 1) {
527
			if (strcasecmp(rcopts[i].name, "tabsize") == 0
Chris Allegretta's avatar
Chris Allegretta committed
528
#ifndef DISABLE_OPERATINGDIR
529
				|| strcasecmp(rcopts[i].name, "operatingdir") == 0
Chris Allegretta's avatar
Chris Allegretta committed
530
#endif
531
#ifndef DISABLE_WRAPJUSTIFY
532
				|| strcasecmp(rcopts[i].name, "fill") == 0
533
#endif
534
#ifndef NANO_SMALL
535
				|| strcasecmp(rcopts[i].name, "whitespace") == 0
536
#endif
537
#ifndef DISABLE_JUSTIFY
538
539
540
				|| strcasecmp(rcopts[i].name, "punct") == 0
				|| strcasecmp(rcopts[i].name, "brackets") == 0
				|| strcasecmp(rcopts[i].name, "quotestr") == 0
541
#endif
542
#ifndef NANO_SMALL
543
			        || strcasecmp(rcopts[i].name, "backupdir") == 0
544
#endif
545
#ifndef DISABLE_SPELLER
546
				|| strcasecmp(rcopts[i].name, "speller") == 0
547
#endif
Chris Allegretta's avatar
Chris Allegretta committed
548
				) {
549
			    if (*ptr == '\n' || *ptr == '\0') {
550
				rcfile_error(N_("Option %s requires an argument"), rcopts[i].name);
551
552
553
				continue;
			    }
			    option = ptr;
Chris Allegretta's avatar
Chris Allegretta committed
554
555
556
557
558
559
560
			    if (*option == '"')
				option++;
			    ptr = parse_argument(ptr);
#ifdef DEBUG
			    fprintf(stderr, "option = %s\n", option);
#endif
#ifndef DISABLE_OPERATINGDIR
561
			    if (strcasecmp(rcopts[i].name, "operatingdir") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
562
563
564
				operating_dir = mallocstrcpy(NULL, option);
			    else
#endif
565
#ifndef DISABLE_WRAPJUSTIFY
566
			    if (strcasecmp(rcopts[i].name, "fill") == 0) {
567
				if (!parse_num(option, &wrap_at)) {
568
				    rcfile_error(N_("Requested fill size %s invalid"), option);
569
570
				    wrap_at = -CHARS_FROM_EOL;
				}
571
			    } else
Chris Allegretta's avatar
Chris Allegretta committed
572
#endif
573
#ifndef NANO_SMALL
574
			    if (strcasecmp(rcopts[i].name, "whitespace") == 0) {
575
576
577
578
				size_t ws_len;
				whitespace = mallocstrcpy(NULL, option);
				ws_len = strlen(whitespace);
				if (ws_len != 2 || (ws_len == 2 && (is_cntrl_char(whitespace[0]) || is_cntrl_char(whitespace[1])))) {
579
				    rcfile_error(N_("Two non-control characters required"));
580
581
				    free(whitespace);
				    whitespace = NULL;
582
				}
583
584
			    } else
#endif
585
#ifndef DISABLE_JUSTIFY
586
			    if (strcasecmp(rcopts[i].name, "punct") == 0) {
587
588
				punct = mallocstrcpy(NULL, option);
				if (strchr(punct, '\t') != NULL || strchr(punct, ' ') != NULL) {
589
				    rcfile_error(N_("Non-tab and non-space characters required"));
590
591
592
				    free(punct);
				    punct = NULL;
				}
593
			    } else if (strcasecmp(rcopts[i].name, "brackets") == 0) {
594
595
				brackets = mallocstrcpy(NULL, option);
				if (strchr(brackets, '\t') != NULL || strchr(brackets, ' ') != NULL) {
596
				    rcfile_error(N_("Non-tab and non-space characters required"));
597
598
599
				    free(brackets);
				    brackets = NULL;
				}
600
			    } else if (strcasecmp(rcopts[i].name, "quotestr") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
601
				quotestr = mallocstrcpy(NULL, option);
602
			    else
603
#endif
604
#ifndef NANO_SMALL
605
			    if (strcasecmp(rcopts[i].name, "backupdir") == 0)
606
607
608
				backup_dir = mallocstrcpy(NULL, option);
			    else
#endif
609
#ifndef DISABLE_SPELLER
610
			    if (strcasecmp(rcopts[i].name, "speller") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
611
612
				alt_speller = mallocstrcpy(NULL, option);
			    else
613
#endif
614
			    if (strcasecmp(rcopts[i].name, "tabsize") == 0) {
615
				if (!parse_num(option, &tabsize) || tabsize <= 0) {
616
				    rcfile_error(N_("Requested tab size %s invalid"), option);
617
				    tabsize = -1;
618
				}
619
			    }
620
			} else
621
622
			    SET(rcopts[i].flag);
#ifdef DEBUG
623
			fprintf(stderr, "set flag %ld!\n",
624
				rcopts[i].flag);
625
626
627
628
#endif
		    } else {
			UNSET(rcopts[i].flag);
#ifdef DEBUG
629
			fprintf(stderr, "unset flag %ld!\n",
630
				rcopts[i].flag);
631
#endif
632
		    }
633
634
635
636
		}
	    }
	}
    }
Chris Allegretta's avatar
Chris Allegretta committed
637
    free(buf);
638
639
640
641
642
643
644
645

    if (errors) {
	errors = FALSE;
	fprintf(stderr, _("\nPress Return to continue starting nano\n"));
	while (getchar() != '\n')
	    ;
    }

646
647
648
649
650
651
652
653
    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
654
655
#ifdef SYSCONFDIR
    assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
656
    nanorc = SYSCONFDIR "/nanorc";
657
    /* Try to open system nanorc */
658
659
    rcstream = fopen(nanorc, "r");
    if (rcstream != NULL) {
Chris Allegretta's avatar
Chris Allegretta committed
660
661
662
663
664
	/* Parse it! */
	parse_rcfile(rcstream);
	fclose(rcstream);
    }
#endif
665

Chris Allegretta's avatar
Chris Allegretta committed
666
    lineno = 0;
Chris Allegretta's avatar
Chris Allegretta committed
667

668
669
    {
	const char *homenv = getenv("HOME");
670

671
672
673
	/* Rely on $HOME, fall back on getpwuid() */
	if (homenv == NULL) {
	    const struct passwd *userage = getpwuid(geteuid());
674

675
676
	    if (userage != NULL)
		homenv = userage->pw_dir;
677
	}
678
	homedir = mallocstrcpy(NULL, homenv);
679
680
    }

681
682
683
684
685
686
687
688
689
690
    if (homedir == NULL) {
	rcfile_error(N_("I can't find my home directory!  Wah!"));
	SET(NO_RCFILE);
    } else {
	size_t homelen = strlen(homedir);
	char *nanorcf = charalloc(homelen + 9);

	nanorc = nanorcf;
	strcpy(nanorcf, homedir);
	strcpy(nanorcf + homelen, "/.nanorc");
Chris Allegretta's avatar
Chris Allegretta committed
691

692
#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
693
    /* If we've already read SYSCONFDIR/nanorc (if it's there), we're
694
       root, and --disable-wrapping-as-root is used, turn wrapping off */
695
	if (geteuid() == NANO_ROOT_UID)
696
697
	    SET(NO_WRAP);
#endif
698
699
	rcstream = fopen(nanorc, "r");
	if (rcstream == NULL) {
Chris Allegretta's avatar
Chris Allegretta committed
700
	    /* Don't complain about the file not existing */
701
	    if (errno != ENOENT) {
702
		rcfile_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
703
704
		SET(NO_RCFILE);
	    }
Chris Allegretta's avatar
Chris Allegretta committed
705
706
707
708
	} else {
	    parse_rcfile(rcstream);
	    fclose(rcstream);
	}
709
	free(nanorcf);
710
    }
711
    lineno = 0;
712

713
714
715
#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
716
717
}

718
#endif /* ENABLE_NANORC */