rcfile.c 16.7 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
53
54
#ifndef NANO_SMALL
    {"historylog", HISTORYLOG},
#endif
55
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
56
    {"mouse", USE_MOUSE},
57
58
59
60
61
62
63
#endif
#ifdef ENABLE_MULTIBUFFER
    {"multibuffer", MULTIBUFFER},
#endif
#ifndef NANO_SMALL
    {"noconvert", NO_CONVERT},
#endif
64
    {"nofollow", NOFOLLOW_SYMLINKS},
65
    {"nohelp", NO_HELP},
Chris Allegretta's avatar
Chris Allegretta committed
66
#ifndef DISABLE_WRAPPING
67
    {"nowrap", NO_WRAP},
Chris Allegretta's avatar
Chris Allegretta committed
68
#endif
69
#ifndef DISABLE_OPERATINGDIR
70
    {"operatingdir", 0},
71
#endif
Chris Allegretta's avatar
Chris Allegretta committed
72
    {"preserve", PRESERVE},
73
    {"rebinddelete", REBIND_DELETE},
74
#ifndef DISABLE_JUSTIFY
75
76
77
78
79
80
81
82
83
    {"quotestr", 0},
#endif
#ifdef HAVE_REGEX_H
    {"regexp", USE_REGEXP},
#endif
#ifndef NANO_SMALL
    {"smooth", SMOOTHSCROLL},
#endif
#ifndef DISABLE_SPELLER
84
    {"speller", 0},
85
86
87
#endif
    {"suspend", SUSPEND},
    {"tabsize", 0},
88
89
    {"tempfile", TEMP_OPT},
    {"view", VIEW_MODE},
90
    {NULL, 0}
91
};
92

93
94
95
96
static int errors = 0;
static int lineno = 0;
static char *nanorc;

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

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

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

112
    while (getchar() != '\n');
113
114
}

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

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

Chris Allegretta's avatar
Chris Allegretta committed
130
/* Parse the next word from the string.  Returns NULL if we hit EOL. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
131
char *parse_next_word(char *ptr)
132
{
133
134
135
136
137
138
139
140
141
    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
142
    while (*ptr == ' ' || *ptr == '\t')
143
144
145
146
	ptr++;

    return ptr;
}
147

Chris Allegretta's avatar
Chris Allegretta committed
148
149
150
151
152
153
/* 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
154
155
char *parse_argument(char *ptr)
{
Chris Allegretta's avatar
Chris Allegretta committed
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    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';
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
175
	rcfile_error(_("Argument %s has unterminated \""), ptr_bak);
Chris Allegretta's avatar
Chris Allegretta committed
176
177
178
179
180
181
182
183
184
185
186
187
    } 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
188
int colortoint(const char *colorname, int *bright)
189
190
191
192
193
194
{
    int mcolor = 0;

    if (colorname == NULL)
	return -1;

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

200
    if (!strcasecmp(colorname, "green"))
Chris Allegretta's avatar
Chris Allegretta committed
201
	mcolor = COLOR_GREEN;
202
    else if (!strcasecmp(colorname, "red"))
Chris Allegretta's avatar
Chris Allegretta committed
203
	mcolor = COLOR_RED;
204
    else if (!strcasecmp(colorname, "blue"))
Chris Allegretta's avatar
Chris Allegretta committed
205
	mcolor = COLOR_BLUE;
206
    else if (!strcasecmp(colorname, "white"))
Chris Allegretta's avatar
Chris Allegretta committed
207
	mcolor = COLOR_WHITE;
208
    else if (!strcasecmp(colorname, "yellow"))
Chris Allegretta's avatar
Chris Allegretta committed
209
	mcolor = COLOR_YELLOW;
210
    else if (!strcasecmp(colorname, "cyan"))
Chris Allegretta's avatar
Chris Allegretta committed
211
	mcolor = COLOR_CYAN;
212
    else if (!strcasecmp(colorname, "magenta"))
Chris Allegretta's avatar
Chris Allegretta committed
213
	mcolor = COLOR_MAGENTA;
214
    else if (!strcasecmp(colorname, "black"))
Chris Allegretta's avatar
Chris Allegretta committed
215
	mcolor = COLOR_BLACK;
216
    else {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
217
218
219
220
221
	rcfile_error(_("Color %s not understood.\n"
			"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);
222
	mcolor = -1;
223
224
225
226
    }
    return mcolor;
}

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
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;
}

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/* 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
262
void parse_syntax(char *ptr)
263
264
{
    syntaxtype *tmpsyntax = NULL;
Chris Allegretta's avatar
Chris Allegretta committed
265
    const char *fileregptr = NULL, *nameptr = NULL;
266
267
    exttype *endext = NULL;
	/* The end of the extensions list for this syntax. */
268
269
270
271
272
273
274
275

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

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

    if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
276
	rcfile_error(_("Regex strings must begin and end with a \" character\n"));
277
	return;
278
279
280
281
282
283
284
285
    }
    ptr++;

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

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

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

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

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

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

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);

327
328
329
330
331
332
333
334
335
336
	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;
337
	}
338
    }
339
340
}

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

    fgstr = ptr;
    ptr = parse_next_word(ptr);

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

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

370
    fg = colortoint(fgstr, &bright);
371

372
373
374
375
    /* Don't try and parse screwed up fg colors */
    if (fg == -1)
	return;

376
377
    if (syntaxes == NULL) {
	rcfile_error(_("Cannot add a color directive without a syntax line"));
378
	return;
379
380
381
382
383
384
    }

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

385
    /* Now the fun part, start adding regexps to individual strings
386
       in the colorstrings array, woo! */
387

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

394
395
396
397
398
399
400
401
402
403
404
405
	while (*ptr == ' ')
	    ptr++;

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

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

	if (*ptr != '"') {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
406
	    rcfile_error(_("Regex strings must begin and end with a \" character\n"));
407
	    ptr = parse_next_regex(ptr);
408
409
410
	    continue;
	}
	ptr++;
411

412
413
414
415
416
417
	newcolor = (colortype *)nmalloc(sizeof(colortype));
	fgstr = ptr;
	ptr = parse_next_regex(ptr);
	if (nregcomp(&newcolor->start, fgstr, 0)) {
	    free(newcolor);
	    cancelled = 1;
418
	} else {
419
420
421
422
423
424
425
426
	    newcolor->fg = fg;
	    newcolor->bg = bg;
	    newcolor->bright = bright;
	    newcolor->next = NULL;
	    newcolor->end = NULL;

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

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

449
	    ptr += 4;
450

451
452
	    if (*ptr != '"') {
		rcfile_error(_
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
453
			     ("Regex strings must begin and end with a \" character\n"));
454
		continue;
455
456
457
	    }
	    ptr++;

458
	    fgstr = ptr;
459
	    ptr = parse_next_regex(ptr);
460
461
462
463
464
465
466
467
468
469

	    /* 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
470
	}
471
    }
472
}
473
474

#endif /* ENABLE_COLOR */
475

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

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

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

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

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

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

Chris Allegretta's avatar
Chris Allegretta committed
569
570
				/* Using strtol() instead of atoi() lets
				 * us accept 0 while checking other
Chris Allegretta's avatar
Chris Allegretta committed
571
572
573
				 * errors. */
				j = (int)strtol(option, &first_error, 10);
				if (errno == ERANGE || *option == '\0' || *first_error != '\0')
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
574
				    rcfile_error(_("Requested fill size %d invalid"),
575
						 j);
Chris Allegretta's avatar
Chris Allegretta committed
576
577
				else
				    wrap_at = j;
578
			    } else
Chris Allegretta's avatar
Chris Allegretta committed
579
#endif
580
#ifndef DISABLE_JUSTIFY
Chris Allegretta's avatar
Chris Allegretta committed
581
582
583
			    if (!strcasecmp(rcopts[i].name, "quotestr"))
				quotestr = mallocstrcpy(NULL, option);
			    else
584
#endif
585
#ifndef DISABLE_SPELLER
Chris Allegretta's avatar
Chris Allegretta committed
586
587
588
			    if (!strcasecmp(rcopts[i].name, "speller"))
				alt_speller = mallocstrcpy(NULL, option);
			    else
589
#endif
Chris Allegretta's avatar
Chris Allegretta committed
590
591
592
593
594
595
596
597
			    {
				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')
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
598
				    rcfile_error(_("Requested tab size %d invalid"),
Chris Allegretta's avatar
Chris Allegretta committed
599
600
601
						 j);
				else
				    tabsize = j;
602
			    }
603
			} else
604
605
			    SET(rcopts[i].flag);
#ifdef DEBUG
606
			fprintf(stderr, "set flag %d!\n",
607
				rcopts[i].flag);
608
609
610
611
#endif
		    } else {
			UNSET(rcopts[i].flag);
#ifdef DEBUG
612
			fprintf(stderr, "unset flag %d!\n",
613
				rcopts[i].flag);
614
#endif
615
		    }
616
617
618
619
		}
	    }
	}
    }
Chris Allegretta's avatar
Chris Allegretta committed
620
    free(buf);
621
622
623
624
625
626
627
628
629
630
    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
631
632
    const struct passwd *userage;
    uid_t euid = geteuid();
633
    char *homenv = getenv("HOME");
634

Chris Allegretta's avatar
Chris Allegretta committed
635
636
637
#ifdef SYSCONFDIR
    assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
    nanorc = charalloc(sizeof(SYSCONFDIR) + 7);
638
639
    sprintf(nanorc, "%s/nanorc", SYSCONFDIR);
    /* Try to open system nanorc */
Chris Allegretta's avatar
Chris Allegretta committed
640
641
642
643
644
645
    if ((rcstream = fopen(nanorc, "r")) != NULL) {
	/* Parse it! */
	parse_rcfile(rcstream);
	fclose(rcstream);
    }
#endif
646

Chris Allegretta's avatar
Chris Allegretta committed
647
    lineno = 0;
Chris Allegretta's avatar
Chris Allegretta committed
648

649
    /* Rely on $HOME, fall back on getpwuid() */
650
    if (homenv != NULL) {
David Lawrence Ramsey's avatar
   
David Lawrence Ramsey committed
651
	nanorc = charealloc(nanorc, strlen(homenv) + 10);
652
	sprintf(nanorc, "%s/.nanorc", homenv);
653
    } else {
654
655
656
657
658
659
660
	userage = getpwuid(euid);
	endpwent();

	if (userage == NULL) {
	    rcfile_error(_("I can't find my home directory!  Wah!"));
	    SET(NO_RCFILE);
	} else {
David Lawrence Ramsey's avatar
   
David Lawrence Ramsey committed
661
	    nanorc = charealloc(nanorc, strlen(userage->pw_dir) + 9);
662
663
664
665
666
667
	    sprintf(nanorc, "%s/.nanorc", userage->pw_dir);

	}
    }

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

669
670
671
672
673
674
#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
675
676
	if ((rcstream = fopen(nanorc, "r")) == NULL) {
	    /* Don't complain about the file not existing */
677
	    if (errno != ENOENT) {
Chris Allegretta's avatar
Chris Allegretta committed
678
679
		rcfile_error(_("Unable to open ~/.nanorc file, %s"),
			strerror(errno));
680
681
		SET(NO_RCFILE);
	    }
Chris Allegretta's avatar
Chris Allegretta committed
682
683
684
685
	} else {
	    parse_rcfile(rcstream);
	    fclose(rcstream);
	}
686
    }
687
    lineno = 0;
688

Chris Allegretta's avatar
Chris Allegretta committed
689
    free(nanorc);
690
691
692
#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
693
694
}

695
#endif /* ENABLE_NANORC */