rcfile.c 16.5 KB
Newer Older
1
2
/* $Id$ */
/**************************************************************************
3
 *   rcfile.c                                                             *
4
 *                                                                        *
5
 *   Copyright (C) 1999-2003 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
32
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
Chris Allegretta's avatar
Chris Allegretta committed
33
#include <pwd.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
44
45
46
    {"backup", BACKUP_FILE},
#endif
    {"const", CONSTUPDATE},
#ifndef NANO_SMALL
47
    {"cut", CUT_TO_END},
48
#endif
Chris Allegretta's avatar
Chris Allegretta committed
49
#ifndef DISABLE_WRAPJUSTIFY
50
    {"fill", 0},
Chris Allegretta's avatar
Chris Allegretta committed
51
#endif
52
    {"keypad", ALT_KEYPAD},
53
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
54
    {"mouse", USE_MOUSE},
55
56
57
58
59
60
61
#endif
#ifdef ENABLE_MULTIBUFFER
    {"multibuffer", MULTIBUFFER},
#endif
#ifndef NANO_SMALL
    {"noconvert", NO_CONVERT},
#endif
62
    {"nofollow", NOFOLLOW_SYMLINKS},
63
    {"nohelp", NO_HELP},
Chris Allegretta's avatar
Chris Allegretta committed
64
#ifndef DISABLE_WRAPPING
65
    {"nowrap", NO_WRAP},
Chris Allegretta's avatar
Chris Allegretta committed
66
#endif
67
#ifndef DISABLE_OPERATINGDIR
68
    {"operatingdir", 0},
69
#endif
Chris Allegretta's avatar
Chris Allegretta committed
70
    {"preserve", PRESERVE},
71
#ifndef DISABLE_JUSTIFY
72
73
74
75
76
77
78
79
80
    {"quotestr", 0},
#endif
#ifdef HAVE_REGEX_H
    {"regexp", USE_REGEXP},
#endif
#ifndef NANO_SMALL
    {"smooth", SMOOTHSCROLL},
#endif
#ifndef DISABLE_SPELLER
81
    {"speller", 0},
82
83
84
#endif
    {"suspend", SUSPEND},
    {"tabsize", 0},
85
86
    {"tempfile", TEMP_OPT},
    {"view", VIEW_MODE},
87
    {"historylog", HISTORYLOG},
88
    {NULL, 0}
89
};
90

91
92
93
94
static int errors = 0;
static int lineno = 0;
static char *nanorc;

95
/* We have an error in some part of the rcfile; put it on stderr and
Chris Allegretta's avatar
Chris Allegretta committed
96
   make the user hit return to continue starting up nano. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
97
void rcfile_error(const char *msg, ...)
98
99
100
101
{
    va_list ap;

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

105
106
107
108
109
    va_start(ap, msg);
    vfprintf(stderr, msg, ap);
    va_end(ap);
    fprintf(stderr, _("\nPress return to continue starting nano\n"));

110
    while (getchar() != '\n');
111
112
}

Chris Allegretta's avatar
Chris Allegretta committed
113
/* Just print the error (one of many, perhaps) but don't abort, yet. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
114
void rcfile_msg(const char *msg, ...)
115
116
117
{
    va_list ap;

118
119
    if (!errors) {
	errors = 1;
120
121
122
123
124
125
126
127
	fprintf(stderr, "\n");
    }
    va_start(ap, msg);
    vfprintf(stderr, msg, ap);
    va_end(ap);
    fprintf(stderr, "\n");
}

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

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

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

Chris Allegretta's avatar
Chris Allegretta committed
140
    while (*ptr == ' ' || *ptr == '\t')
141
142
143
144
	ptr++;

    return ptr;
}
145

Chris Allegretta's avatar
Chris Allegretta committed
146
147
148
149
150
151
/* The keywords operatingdir, fill, tabsize, speller, and quotestr take
 * an argument when set.  Among these, operatingdir, speller, and
 * quotestr 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
152
153
char *parse_argument(char *ptr)
{
Chris Allegretta's avatar
Chris Allegretta committed
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
    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';
	rcfile_error(_("argument %s has unterminated \""), ptr_bak);
    } else {
	*last_quote = '\0';
	ptr = last_quote + 1;
    }
    if (ptr != NULL)
	while (*ptr == ' ' || *ptr == '\t')
	    ptr++;
    return ptr;
}

#ifdef ENABLE_COLOR

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

    if (colorname == NULL)
	return -1;

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

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

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
char *parse_next_regex(char *ptr)
{
    while ((*ptr != '"' || (*(ptr + 1) != ' ' && *(ptr + 1) != '\n'))
	   && *ptr != '\n' && *ptr != '\0')
	ptr++;

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

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

    while (*ptr == ' ' || *ptr == '\t')
	ptr++;

    return ptr;
}

243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* Compile the regular expression regex to preg.  Returns FALSE on success,
   TRUE if the expression is invalid. */
int nregcomp(regex_t *preg, const char *regex, int flags)
{
    int rc = regcomp(preg, regex, REG_EXTENDED | flags);

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

	regerror(rc, preg, str, len);
	rcfile_error(_("Bad regex \"%s\": %s"), regex, str);
	free(str);
    }
    return rc != 0;
}

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

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

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

    if (*ptr != '"') {
	rcfile_error(_("regex strings must begin and end with a \" character\n"));
275
	return;
276
277
278
279
280
281
282
283
    }
    ptr++;

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

    if (ptr == NULL) {
	rcfile_error(_("Missing syntax name"));
284
	return;
285
286
    }

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

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

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

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

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);

325
326
327
328
329
330
331
332
333
334
	newext = (exttype *)nmalloc(sizeof(exttype));
	if (nregcomp(&newext->val, fileregptr, REG_NOSUB))
	    free(newext);
	else {
	    if (endext == NULL)
		tmpsyntax->extensions = newext;
	    else
		endext->next = newext;
	    endext = newext;
	    endext->next = NULL;
335
	}
336
    }
337
338
}

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

    fgstr = ptr;
    ptr = parse_next_word(ptr);

    if (ptr == NULL) {
352
	rcfile_error(_("Missing color name"));
353
	return;
354
355
356
357
    }

    if (strstr(fgstr, ",")) {
	strtok(fgstr, ",");
Chris Allegretta's avatar
Chris Allegretta committed
358
	bg = colortoint(strtok(NULL, ","), &bright);
359
    } else
Chris Allegretta's avatar
Chris Allegretta committed
360
	bg = -1;
361

362
    fg = colortoint(fgstr, &bright);
363

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

368
369
    if (syntaxes == NULL) {
	rcfile_error(_("Cannot add a color directive without a syntax line"));
370
	return;
371
372
373
374
375
376
    }

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

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

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

386
387
388
389
390
391
392
393
394
395
396
397
398
	while (*ptr == ' ')
	    ptr++;

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

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

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

404
405
406
407
408
409
	newcolor = (colortype *)nmalloc(sizeof(colortype));
	fgstr = ptr;
	ptr = parse_next_regex(ptr);
	if (nregcomp(&newcolor->start, fgstr, 0)) {
	    free(newcolor);
	    cancelled = 1;
410
	} else {
411
412
413
414
415
416
417
418
	    newcolor->fg = fg;
	    newcolor->bg = bg;
	    newcolor->bright = bright;
	    newcolor->next = NULL;
	    newcolor->end = NULL;

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

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

441
	    ptr += 4;
442

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

450
	    fgstr = ptr;
451
	    ptr = parse_next_regex(ptr);
452
453
454
455
456
457
458
459
460
461

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

#endif /* ENABLE_COLOR */
467

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

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

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

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

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

	/* Else try to parse the keyword */
	if (!strcasecmp(keyword, "set"))
	    set = 1;
	else if (!strcasecmp(keyword, "unset"))
	    set = -1;
502
#ifdef ENABLE_COLOR
503
	else if (!strcasecmp(keyword, "syntax"))
Chris Allegretta's avatar
Chris Allegretta committed
504
	    parse_syntax(ptr);
505
	else if (!strcasecmp(keyword, "color"))
Chris Allegretta's avatar
Chris Allegretta committed
506
	    parse_colors(ptr);
507
#endif				/* ENABLE_COLOR */
508
	else {
509
	    rcfile_msg(_("command %s not understood"), keyword);
510
511
512
513
514
515
516
517
	    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) {
518
	    for (i = 0; rcopts[i].name != NULL; i++) {
519
		if (!strcasecmp(option, rcopts[i].name)) {
520
#ifdef DEBUG
521
522
		    fprintf(stderr, _("%s: Parsing option %s\n"), 
			    "parse_rcfile()", rcopts[i].name);
523
#endif
524
		    if (set == 1) {
Chris Allegretta's avatar
Chris Allegretta committed
525
526
527
528
			if (!strcasecmp(rcopts[i].name, "tabsize")
#ifndef DISABLE_OPERATINGDIR
				|| !strcasecmp(rcopts[i].name, "operatingdir")
#endif
529
#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta's avatar
Chris Allegretta committed
530
				|| !strcasecmp(rcopts[i].name, "fill")
531
#endif
532
#ifndef DISABLE_JUSTIFY
Chris Allegretta's avatar
Chris Allegretta committed
533
				|| !strcasecmp(rcopts[i].name, "quotestr")
534
#endif
535
#ifndef DISABLE_SPELLER
Chris Allegretta's avatar
Chris Allegretta committed
536
				|| !strcasecmp(rcopts[i].name, "speller")
537
#endif
Chris Allegretta's avatar
Chris Allegretta committed
538
				) {
539
			    if (*ptr == '\n' || *ptr == '\0') {
540
541
542
				rcfile_error(_
					     ("option %s requires an argument"),
					     rcopts[i].name);
543
544
545
				continue;
			    }
			    option = ptr;
Chris Allegretta's avatar
Chris Allegretta committed
546
547
548
549
550
551
552
553
554
555
556
			    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
557
#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta's avatar
Chris Allegretta committed
558
559
560
			    if (!strcasecmp(rcopts[i].name, "fill")) {
				char *first_error;

Chris Allegretta's avatar
Chris Allegretta committed
561
562
				/* Using strtol() instead of atoi() lets
				 * us accept 0 while checking other
Chris Allegretta's avatar
Chris Allegretta committed
563
564
565
566
				 * errors. */
				j = (int)strtol(option, &first_error, 10);
				if (errno == ERANGE || *option == '\0' || *first_error != '\0')
				    rcfile_error(_("requested fill size %d invalid"),
567
						 j);
Chris Allegretta's avatar
Chris Allegretta committed
568
569
				else
				    wrap_at = j;
570
			    } else
Chris Allegretta's avatar
Chris Allegretta committed
571
#endif
572
#ifndef DISABLE_JUSTIFY
Chris Allegretta's avatar
Chris Allegretta committed
573
574
575
			    if (!strcasecmp(rcopts[i].name, "quotestr"))
				quotestr = mallocstrcpy(NULL, option);
			    else
576
#endif
577
#ifndef DISABLE_SPELLER
Chris Allegretta's avatar
Chris Allegretta committed
578
579
580
			    if (!strcasecmp(rcopts[i].name, "speller"))
				alt_speller = mallocstrcpy(NULL, option);
			    else
581
#endif
Chris Allegretta's avatar
Chris Allegretta committed
582
583
584
585
586
587
588
589
590
591
592
593
			    {
				char *first_error;

				/* Using strtol instead of atoi lets us
				 * accept 0 while checking other
				 * errors. */
				j = (int)strtol(option, &first_error, 10);
				if (errno == ERANGE || *option == '\0' || *first_error != '\0')
				    rcfile_error(_("requested tab size %d invalid"),
						 j);
				else
				    tabsize = j;
594
			    }
595
			} else
596
597
			    SET(rcopts[i].flag);
#ifdef DEBUG
598
599
			fprintf(stderr, _("set flag %d!\n"),
				rcopts[i].flag);
600
601
602
603
#endif
		    } else {
			UNSET(rcopts[i].flag);
#ifdef DEBUG
604
605
			fprintf(stderr, _("unset flag %d!\n"),
				rcopts[i].flag);
606
#endif
607
		    }
608
609
610
611
		}
	    }
	}
    }
Chris Allegretta's avatar
Chris Allegretta committed
612
    free(buf);
613
614
615
616
617
618
619
620
621
622
    if (errors)
	rcfile_error(_("Errors found in .nanorc file"));

    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
623
624
    const struct passwd *userage;
    uid_t euid = geteuid();
625
    char *homenv = getenv("HOME");
626

Chris Allegretta's avatar
Chris Allegretta committed
627
628
629
#ifdef SYSCONFDIR
    assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
    nanorc = charalloc(sizeof(SYSCONFDIR) + 7);
630
631
    sprintf(nanorc, "%s/nanorc", SYSCONFDIR);
    /* Try to open system nanorc */
Chris Allegretta's avatar
Chris Allegretta committed
632
633
634
635
636
637
    if ((rcstream = fopen(nanorc, "r")) != NULL) {
	/* Parse it! */
	parse_rcfile(rcstream);
	fclose(rcstream);
    }
#endif
638

Chris Allegretta's avatar
Chris Allegretta committed
639
    lineno = 0;
Chris Allegretta's avatar
Chris Allegretta committed
640

641
    /* Rely on $HOME, fall back on getpwuid() */
642
643
644
    if (homenv != NULL) {
	nanorc = nrealloc(nanorc, strlen(homenv) + 10);
	sprintf(nanorc, "%s/.nanorc", homenv);
645
    } else {
646
647
648
649
650
651
652
653
654
655
656
657
658
659
	userage = getpwuid(euid);
	endpwent();

	if (userage == NULL) {
	    rcfile_error(_("I can't find my home directory!  Wah!"));
	    SET(NO_RCFILE);
	} else {
	    nanorc = nrealloc(nanorc, strlen(userage->pw_dir) + 9);
	    sprintf(nanorc, "%s/.nanorc", userage->pw_dir);

	}
    }

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

661
662
663
664
665
666
#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
    /* If we've already read $SYSCONFDIR/nanorc (if it's there), we're
       root, and --disable-wrapping-as-root is used, turn wrapping off */
	if (euid == 0)
	    SET(NO_WRAP);
#endif
Chris Allegretta's avatar
Chris Allegretta committed
667
668
	if ((rcstream = fopen(nanorc, "r")) == NULL) {
	    /* Don't complain about the file not existing */
669
	    if (errno != ENOENT) {
Chris Allegretta's avatar
Chris Allegretta committed
670
671
		rcfile_error(_("Unable to open ~/.nanorc file, %s"),
			strerror(errno));
672
673
		SET(NO_RCFILE);
	    }
Chris Allegretta's avatar
Chris Allegretta committed
674
675
676
677
	} else {
	    parse_rcfile(rcstream);
	    fclose(rcstream);
	}
678
679
    }

Chris Allegretta's avatar
Chris Allegretta committed
680
    free(nanorc);
681
682
683
#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
684
685
}

686
#endif /* ENABLE_NANORC */