rcfile.c 16.9 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
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
    {"backup", BACKUP_FILE},
44
    {"backupdir", 0},
45
46
47
#endif
    {"const", CONSTUPDATE},
#ifndef NANO_SMALL
48
    {"cut", CUT_TO_END},
49
#endif
Chris Allegretta's avatar
Chris Allegretta committed
50
#ifndef DISABLE_WRAPJUSTIFY
51
    {"fill", 0},
Chris Allegretta's avatar
Chris Allegretta committed
52
#endif
53
54
55
#ifndef NANO_SMALL
    {"historylog", HISTORYLOG},
#endif
56
#ifndef DISABLE_MOUSE
57
    {"mouse", USE_MOUSE},
58
59
60
61
62
63
64
#endif
#ifdef ENABLE_MULTIBUFFER
    {"multibuffer", MULTIBUFFER},
#endif
#ifndef NANO_SMALL
    {"noconvert", NO_CONVERT},
#endif
65
    {"nofollow", NOFOLLOW_SYMLINKS},
66
    {"nohelp", NO_HELP},
Chris Allegretta's avatar
Chris Allegretta committed
67
#ifndef DISABLE_WRAPPING
68
    {"nowrap", NO_WRAP},
Chris Allegretta's avatar
Chris Allegretta committed
69
#endif
70
#ifndef DISABLE_OPERATINGDIR
71
    {"operatingdir", 0},
72
#endif
Chris Allegretta's avatar
Chris Allegretta committed
73
    {"preserve", PRESERVE},
74
    {"rebinddelete", REBIND_DELETE},
75
#ifndef DISABLE_JUSTIFY
76
77
78
79
80
81
82
83
84
    {"quotestr", 0},
#endif
#ifdef HAVE_REGEX_H
    {"regexp", USE_REGEXP},
#endif
#ifndef NANO_SMALL
    {"smooth", SMOOTHSCROLL},
#endif
#ifndef DISABLE_SPELLER
85
    {"speller", 0},
86
87
88
#endif
    {"suspend", SUSPEND},
    {"tabsize", 0},
89
90
    {"tempfile", TEMP_OPT},
    {"view", VIEW_MODE},
91
    {NULL, 0}
92
};
93

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

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

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

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

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

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

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

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

    return ptr;
}
148

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

    if (colorname == NULL)
	return -1;

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

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

228
229
230
231
232
233
234
235
236
char *parse_next_regex(char *ptr)
{
    while ((*ptr != '"' || (*(ptr + 1) != ' ' && *(ptr + 1) != '\n'))
	   && *ptr != '\n' && *ptr != '\0')
	ptr++;

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

237
    /* Null terminate and advance ptr. */
238
239
240
241
242
243
244
245
    *ptr++ = '\0';

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

    return ptr;
}

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

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

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

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

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

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

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

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

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

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

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);

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

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

    fgstr = ptr;
    ptr = parse_next_word(ptr);

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

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

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

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

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

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

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

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

395
396
397
398
399
400
401
402
403
404
405
406
	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
407
	    rcfile_error(_("Regex strings must begin and end with a \" character\n"));
408
	    ptr = parse_next_regex(ptr);
409
410
411
	    continue;
	}
	ptr++;
412

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

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

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

450
	    ptr += 4;
451

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

459
	    fgstr = ptr;
460
	    ptr = parse_next_regex(ptr);
461
462
463
464
465
466

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

#endif /* ENABLE_COLOR */
476

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

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

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

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

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

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

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

Chris Allegretta's avatar
Chris Allegretta committed
644
645
646
#ifdef SYSCONFDIR
    assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
    nanorc = charalloc(sizeof(SYSCONFDIR) + 7);
647
648
    sprintf(nanorc, "%s/nanorc", SYSCONFDIR);
    /* Try to open system nanorc */
Chris Allegretta's avatar
Chris Allegretta committed
649
650
651
652
653
654
    if ((rcstream = fopen(nanorc, "r")) != NULL) {
	/* Parse it! */
	parse_rcfile(rcstream);
	fclose(rcstream);
    }
#endif
655

Chris Allegretta's avatar
Chris Allegretta committed
656
    lineno = 0;
Chris Allegretta's avatar
Chris Allegretta committed
657

658
    /* Rely on $HOME, fall back on getpwuid() */
659
    if (homenv != NULL) {
David Lawrence Ramsey's avatar
   
David Lawrence Ramsey committed
660
	nanorc = charealloc(nanorc, strlen(homenv) + 10);
661
	sprintf(nanorc, "%s/.nanorc", homenv);
662
    } else {
663
664
665
666
667
668
669
	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
670
	    nanorc = charealloc(nanorc, strlen(userage->pw_dir) + 9);
671
672
673
674
675
676
	    sprintf(nanorc, "%s/.nanorc", userage->pw_dir);

	}
    }

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

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

Chris Allegretta's avatar
Chris Allegretta committed
698
    free(nanorc);
699
700
701
#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
702
703
}

704
#endif /* ENABLE_NANORC */