rcfile.c 17.5 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
#include "config.h"

24
#include <stdlib.h>
25
#include <stdarg.h>
26
27
28
#include <string.h>
#include <stdio.h>
#include <errno.h>
Chris Allegretta's avatar
Chris Allegretta committed
29
#include <unistd.h>
30
31
#include <sys/stat.h>
#include <fcntl.h>
Chris Allegretta's avatar
Chris Allegretta committed
32
#include <pwd.h>
33
#include <ctype.h>
Chris Allegretta's avatar
Chris Allegretta committed
34
#include <assert.h>
35
36
37
38
39
#include "proto.h"
#include "nano.h"

#ifdef ENABLE_NANORC

40
const static rcoption rcopts[] = {
41
#ifndef NANO_SMALL
42
    {"autoindent", AUTOINDENT},
43
    {"backup", BACKUP_FILE},
44
    {"backupdir", 0},
45
46
47
#endif
#ifndef DISABLE_JUSTIFY
    {"brackets", 0},
48
49
50
#endif
    {"const", CONSTUPDATE},
#ifndef NANO_SMALL
51
    {"cut", CUT_TO_END},
52
#endif
Chris Allegretta's avatar
Chris Allegretta committed
53
#ifndef DISABLE_WRAPJUSTIFY
54
    {"fill", 0},
Chris Allegretta's avatar
Chris Allegretta committed
55
#endif
56
57
58
#ifndef NANO_SMALL
    {"historylog", HISTORYLOG},
#endif
59
#ifndef DISABLE_MOUSE
60
    {"mouse", USE_MOUSE},
61
62
63
64
65
66
67
#endif
#ifdef ENABLE_MULTIBUFFER
    {"multibuffer", MULTIBUFFER},
#endif
#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
83
84
85
#ifdef HAVE_REGEX_H
    {"regexp", USE_REGEXP},
#endif
#ifndef NANO_SMALL
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
86
    {"smarthome", SMART_HOME},
87
88
89
    {"smooth", SMOOTHSCROLL},
#endif
#ifndef DISABLE_SPELLER
90
    {"speller", 0},
91
92
93
#endif
    {"suspend", SUSPEND},
    {"tabsize", 0},
94
    {"tempfile", TEMP_FILE},
95
    {"view", VIEW_MODE},
96
97
98
#ifndef NANO_SMALL
    {"whitespace", 0},
#endif
99
    {NULL, 0}
100
};
101

102
103
104
static int lineno = 0;
static char *nanorc;

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

    fprintf(stderr, "\n");
Chris Allegretta's avatar
Chris Allegretta committed
112
113
114
    if (lineno > 0)
	fprintf(stderr, _("Error in %s on line %d: "), nanorc, lineno);

115
    va_start(ap, msg);
116
    vfprintf(stderr, _(msg), ap);
117
    va_end(ap);
118
    fprintf(stderr, _("\nPress Return to continue\n"));
119

120
121
    while (getchar() != '\n')
	;
122
123
}

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

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

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

136
    while (isblank(*ptr))
137
138
139
140
	ptr++;

    return ptr;
}
141

142
/* The keywords operatingdir, backupdir, fill, tabsize, speller,
143
144
145
146
147
148
 * 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
149
150
char *parse_argument(char *ptr)
{
Chris Allegretta's avatar
Chris Allegretta committed
151
152
153
154
155
156
157
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;
    } while (*ptr != '\n' && *ptr != '\0');

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

#ifdef ENABLE_COLOR

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

    if (colorname == NULL)
	return -1;

Chris Allegretta's avatar
Chris Allegretta committed
190
    if (!strncasecmp(colorname, "bright", 6)) {
191
	*bright = 1;
192
193
	colorname += 6;
    }
194

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

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

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

231
    /* Null terminate and advance ptr. */
232
233
    *ptr++ = '\0';

234
    while (isblank(*ptr))
235
236
237
238
239
	ptr++;

    return ptr;
}

240
241
242
/* 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)
243
{
244
    int rc = regcomp(preg, regex, REG_EXTENDED | eflags);
245
246
247
248
249
250

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

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

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

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

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

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

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

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

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

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

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

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

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);

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

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

    fgstr = ptr;
    ptr = parse_next_word(ptr);

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

    if (strstr(fgstr, ",")) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
355
	char *bgcolorname;
356
	strtok(fgstr, ",");
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
357
358
	bgcolorname = strtok(NULL, ",");
	if (!strncasecmp(bgcolorname, "bright", 6)) {
359
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
397
398
399
400
401
402
	while (*ptr == ' ')
	    ptr++;

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

	if (!strncasecmp(ptr, "start=", 6)) {
	    ptr += 6;
	    expectend = 1;
	}

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

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

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

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

447
	    ptr += 4;
448

449
	    if (*ptr != '"') {
450
451
		rcfile_error(
			N_("Regex strings must begin and end with a \" character\n"));
452
		continue;
453
454
455
	    }
	    ptr++;

456
	    fgstr = ptr;
457
	    ptr = parse_next_regex(ptr);
458
459
460
461
462
463

	    /* 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
464
	    if (nregcomp(newcolor->end, fgstr, 0) != 0) {
465
466
467
		free(newcolor->end);
		newcolor->end = NULL;
	    }
Chris Allegretta's avatar
Chris Allegretta committed
468
	}
469
    }
470
}
471
472

#endif /* ENABLE_COLOR */
473

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

480
    buf = charalloc(1024);
Chris Allegretta's avatar
Chris Allegretta committed
481
    while (fgets(buf, 1023, rcstream) != 0) {
482
483
	lineno++;
	ptr = buf;
484
	while (isblank(*ptr))
485
486
487
488
489
490
491
	    ptr++;

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

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

	/* Else skip to the next space */
	keyword = ptr;
	ptr = parse_next_word(ptr);
500
	if (ptr == NULL)
501
502
503
504
505
506
507
	    continue;

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

Chris Allegretta's avatar
Chris Allegretta committed
658
659
660
#ifdef SYSCONFDIR
    assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
    nanorc = charalloc(sizeof(SYSCONFDIR) + 7);
661
662
    sprintf(nanorc, "%s/nanorc", SYSCONFDIR);
    /* Try to open system nanorc */
Chris Allegretta's avatar
Chris Allegretta committed
663
664
665
666
667
668
    if ((rcstream = fopen(nanorc, "r")) != NULL) {
	/* Parse it! */
	parse_rcfile(rcstream);
	fclose(rcstream);
    }
#endif
669

Chris Allegretta's avatar
Chris Allegretta committed
670
    lineno = 0;
Chris Allegretta's avatar
Chris Allegretta committed
671

672
    /* Rely on $HOME, fall back on getpwuid() */
673
    if (homenv != NULL) {
David Lawrence Ramsey's avatar
   
David Lawrence Ramsey committed
674
	nanorc = charealloc(nanorc, strlen(homenv) + 10);
675
	sprintf(nanorc, "%s/.nanorc", homenv);
676
    } else {
677
678
679
680
	userage = getpwuid(euid);
	endpwent();

	if (userage == NULL) {
681
	    rcfile_error(N_("I can't find my home directory!  Wah!"));
682
683
	    SET(NO_RCFILE);
	} else {
David Lawrence Ramsey's avatar
   
David Lawrence Ramsey committed
684
	    nanorc = charealloc(nanorc, strlen(userage->pw_dir) + 9);
685
686
687
688
689
690
	    sprintf(nanorc, "%s/.nanorc", userage->pw_dir);

	}
    }

    if (!ISSET(NO_RCFILE)) {
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 (euid == NANO_ROOT_UID)
696
697
	    SET(NO_WRAP);
#endif
Chris Allegretta's avatar
Chris Allegretta committed
698
699
	if ((rcstream = fopen(nanorc, "r")) == NULL) {
	    /* Don't complain about the file not existing */
700
	    if (errno != ENOENT) {
701
		rcfile_error(N_("Unable to open ~/.nanorc file, %s"),
Chris Allegretta's avatar
Chris Allegretta committed
702
			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
    }
710
    lineno = 0;
711

Chris Allegretta's avatar
Chris Allegretta committed
712
    free(nanorc);
713
714
715
#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
716
717
}

718
#endif /* ENABLE_NANORC */