rcfile.c 17.8 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
static bool errors = FALSE;
103
104
105
static int lineno = 0;
static char *nanorc;

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

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

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

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

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

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

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

    return ptr;
}
140

141
/* The keywords operatingdir, backupdir, fill, tabsize, speller,
142
143
144
145
146
147
 * 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
148
149
char *parse_argument(char *ptr)
{
Chris Allegretta's avatar
Chris Allegretta committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
    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';
169
	rcfile_error(N_("Argument %s has unterminated \"\n"), ptr_bak);
Chris Allegretta's avatar
Chris Allegretta committed
170
171
172
173
174
    } else {
	*last_quote = '\0';
	ptr = last_quote + 1;
    }
    if (ptr != NULL)
175
	while (isblank(*ptr))
Chris Allegretta's avatar
Chris Allegretta committed
176
177
178
179
180
181
	    ptr++;
    return ptr;
}

#ifdef ENABLE_COLOR

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

    if (colorname == NULL)
	return -1;

189
    if (strncasecmp(colorname, "bright", 6) == 0) {
190
	*bright = 1;
191
192
	colorname += 6;
    }
193

194
    if (strcasecmp(colorname, "green") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
195
	mcolor = COLOR_GREEN;
196
    else if (strcasecmp(colorname, "red") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
197
	mcolor = COLOR_RED;
198
    else if (strcasecmp(colorname, "blue") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
199
	mcolor = COLOR_BLUE;
200
    else if (strcasecmp(colorname, "white") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
201
	mcolor = COLOR_WHITE;
202
    else if (strcasecmp(colorname, "yellow") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
203
	mcolor = COLOR_YELLOW;
204
    else if (strcasecmp(colorname, "cyan") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
205
	mcolor = COLOR_CYAN;
206
    else if (strcasecmp(colorname, "magenta") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
207
	mcolor = COLOR_MAGENTA;
208
    else if (strcasecmp(colorname, "black") == 0)
Chris Allegretta's avatar
Chris Allegretta committed
209
	mcolor = COLOR_BLACK;
210
    else {
211
	rcfile_error(N_("Color %s not understood.\n"
212
213
214
215
		"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);
216
	mcolor = -1;
217
218
219
220
    }
    return mcolor;
}

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

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

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

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

    return ptr;
}

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

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

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

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

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

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

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

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

    if (ptr == NULL) {
279
	rcfile_error(N_("Missing syntax name\n"));
280
	return;
281
282
    }

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

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

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

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

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);

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

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

    fgstr = ptr;
    ptr = parse_next_word(ptr);

    if (ptr == NULL) {
348
	rcfile_error(N_("Missing color name\n"));
349
	return;
350
351
352
    }

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

364
    fg = colortoint(fgstr, &bright);
365

366
367
368
369
    /* Don't try and parse screwed up fg colors */
    if (fg == -1)
	return;

370
    if (syntaxes == NULL) {
371
	rcfile_error(N_("Cannot add a color directive without a syntax line\n"));
372
	return;
373
374
375
376
377
378
    }

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

379
    /* Now the fun part, start adding regexps to individual strings
380
       in the colorstrings array, woo! */
381

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

388
389
390
391
392
393
	while (*ptr == ' ')
	    ptr++;

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

394
	if (strncasecmp(ptr, "start=", 6) == 0) {
395
396
397
398
399
	    ptr += 6;
	    expectend = 1;
	}

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

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

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

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

441
	    ptr += 4;
442

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

449
	    fgstr = ptr;
450
	    ptr = parse_next_regex(ptr);
451
452
453
454
455
456

	    /* 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
457
	    if (nregcomp(newcolor->end, fgstr, 0) != 0) {
458
459
460
		free(newcolor->end);
		newcolor->end = NULL;
	    }
Chris Allegretta's avatar
Chris Allegretta committed
461
	}
462
    }
463
}
464
465

#endif /* ENABLE_COLOR */
466

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

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

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

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

	/* Else skip to the next space */
	keyword = ptr;
	ptr = parse_next_word(ptr);
493
	if (ptr == NULL)
494
495
496
	    continue;

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

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

642
643
644
645
646
647
648
    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
649
650
    const struct passwd *userage;
    uid_t euid = geteuid();
651
    char *homenv = getenv("HOME");
652

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

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

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

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

	}
    }

    if (!ISSET(NO_RCFILE)) {
Chris Allegretta's avatar
Chris Allegretta committed
686

687
#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
688
    /* If we've already read SYSCONFDIR/nanorc (if it's there), we're
689
       root, and --disable-wrapping-as-root is used, turn wrapping off */
690
	if (euid == NANO_ROOT_UID)
691
692
	    SET(NO_WRAP);
#endif
Chris Allegretta's avatar
Chris Allegretta committed
693
694
	if ((rcstream = fopen(nanorc, "r")) == NULL) {
	    /* Don't complain about the file not existing */
695
	    if (errno != ENOENT) {
696
		rcfile_error(N_("Unable to open ~/.nanorc file: %s\n"), strerror(errno));
697
698
		SET(NO_RCFILE);
	    }
Chris Allegretta's avatar
Chris Allegretta committed
699
700
701
702
	} else {
	    parse_rcfile(rcstream);
	    fclose(rcstream);
	}
703
    }
704
    lineno = 0;
705

Chris Allegretta's avatar
Chris Allegretta committed
706
    free(nanorc);
707
708
709
#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
710
711
}

712
#endif /* ENABLE_NANORC */