"src/global.c" did not exist on "9a46f3cf56f01282b23e8c6d5fafb799e3f554d8"
rcfile.c 17.4 KB
Newer Older
1
2
/* $Id$ */
/**************************************************************************
3
 *   rcfile.c                                                             *
4
 *                                                                        *
5
 *   Copyright (C) 1999-2004 Chris Allegretta                             *
6
7
 *   This program is free software; you can redistribute it and/or modify *
 *   it under the terms of the GNU General Public License as published by *
8
 *   the Free Software Foundation; either version 2, or (at your option)  *
9
10
11
12
13
14
15
16
17
18
19
20
21
 *   any later version.                                                   *
 *                                                                        *
 *   This program is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of       *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
 *   GNU General Public License for more details.                         *
 *                                                                        *
 *   You should have received a copy of the GNU General Public License    *
 *   along with this program; if not, write to the Free Software          *
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
 *                                                                        *
 **************************************************************************/

22
23
#include "config.h"

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

#ifdef ENABLE_NANORC

40
const static rcoption rcopts[] = {
41
#ifndef NANO_SMALL
42
    {"autoindent", AUTOINDENT},
43
    {"backup", BACKUP_FILE},
44
    {"backupdir", 0},
45
46
47
#endif
#ifndef DISABLE_JUSTIFY
    {"brackets", 0},
48
49
50
#endif
    {"const", CONSTUPDATE},
#ifndef NANO_SMALL
51
    {"cut", CUT_TO_END},
52
#endif
Chris Allegretta's avatar
Chris Allegretta committed
53
#ifndef DISABLE_WRAPJUSTIFY
54
    {"fill", 0},
Chris Allegretta's avatar
Chris Allegretta committed
55
#endif
56
57
58
#ifndef NANO_SMALL
    {"historylog", HISTORYLOG},
#endif
59
#ifndef DISABLE_MOUSE
60
    {"mouse", USE_MOUSE},
61
62
63
64
65
66
67
#endif
#ifdef ENABLE_MULTIBUFFER
    {"multibuffer", MULTIBUFFER},
#endif
#ifndef NANO_SMALL
    {"noconvert", NO_CONVERT},
#endif
68
    {"nofollow", NOFOLLOW_SYMLINKS},
69
    {"nohelp", NO_HELP},
Chris Allegretta's avatar
Chris Allegretta committed
70
#ifndef DISABLE_WRAPPING
71
    {"nowrap", NO_WRAP},
Chris Allegretta's avatar
Chris Allegretta committed
72
#endif
73
#ifndef DISABLE_OPERATINGDIR
74
    {"operatingdir", 0},
75
#endif
Chris Allegretta's avatar
Chris Allegretta committed
76
    {"preserve", PRESERVE},
77
#ifndef DISABLE_JUSTIFY
78
    {"punct", 0},
79
80
    {"quotestr", 0},
#endif
81
    {"rebinddelete", REBIND_DELETE},
82
83
84
85
#ifdef HAVE_REGEX_H
    {"regexp", USE_REGEXP},
#endif
#ifndef NANO_SMALL
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
86
    {"smarthome", SMART_HOME},
87
88
89
    {"smooth", SMOOTHSCROLL},
#endif
#ifndef DISABLE_SPELLER
90
    {"speller", 0},
91
92
93
#endif
    {"suspend", SUSPEND},
    {"tabsize", 0},
94
    {"tempfile", TEMP_FILE},
95
    {"view", VIEW_MODE},
96
97
98
#ifndef NANO_SMALL
    {"whitespace", 0},
#endif
99
    {NULL, 0}
100
};
101

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

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

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

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

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

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

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

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

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

    return ptr;
}
141

142
/* The keywords operatingdir, backupdir, fill, tabsize, speller,
143
144
145
146
147
148
 * punct, brackets, quotestr, and whitespace take an argument when set.
 * Among these, operatingdir, backupdir, speller, punct, brackets,
 * quotestr, and whitespace have to allow tabs and spaces in the
 * argument.  Thus, if the next word starts with a ", we say it ends
 * with the last " of the line.  Otherwise, the word is interpreted as
 * usual.  That is so the arguments can contain "s too. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
149
150
char *parse_argument(char *ptr)
{
Chris Allegretta's avatar
Chris Allegretta committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
    const char *ptr_bak = ptr;
    char *last_quote = NULL;

    assert(ptr != NULL);

    if (*ptr != '"')
	return parse_next_word(ptr);

    do {
	ptr++;
	if (*ptr == '"')
	    last_quote = ptr;
    } while (*ptr != '\n' && *ptr != '\0');

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

#ifdef ENABLE_COLOR

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

    if (colorname == NULL)
	return -1;

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

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

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

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

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

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

    return ptr;
}

240
241
242
/* Compile the regular expression regex to preg.  Returns FALSE on
 * success, or TRUE if the expression is invalid. */
int nregcomp(regex_t *preg, const char *regex, int eflags)
243
{
244
    int rc = regcomp(preg, regex, REG_EXTENDED | eflags);
245
246
247
248
249
250

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

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

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

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

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

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

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

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

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

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

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

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

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);

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

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

    fgstr = ptr;
    ptr = parse_next_word(ptr);

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

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

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

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

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

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

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

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

389
390
391
392
393
394
395
396
397
398
399
400
	while (*ptr == ' ')
	    ptr++;

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

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

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

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

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

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

443
	    ptr += 4;
444

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

451
	    fgstr = ptr;
452
	    ptr = parse_next_regex(ptr);
453
454
455
456
457
458

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

#endif /* ENABLE_COLOR */
468

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

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

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

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

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

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

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

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

659
    /* Rely on $HOME, fall back on getpwuid() */
660
    if (homenv != NULL) {
David Lawrence Ramsey's avatar
   
David Lawrence Ramsey committed
661
	nanorc = charealloc(nanorc, strlen(homenv) + 10);
662
	sprintf(nanorc, "%s/.nanorc", homenv);
663
    } else {
664
665
666
667
	userage = getpwuid(euid);
	endpwent();

	if (userage == NULL) {
668
	    rcfile_error(N_("I can't find my home directory!  Wah!"));
669
670
	    SET(NO_RCFILE);
	} else {
David Lawrence Ramsey's avatar
   
David Lawrence Ramsey committed
671
	    nanorc = charealloc(nanorc, strlen(userage->pw_dir) + 9);
672
673
674
675
676
677
	    sprintf(nanorc, "%s/.nanorc", userage->pw_dir);

	}
    }

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

679
#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
680
    /* If we've already read SYSCONFDIR/nanorc (if it's there), we're
681
       root, and --disable-wrapping-as-root is used, turn wrapping off */
682
	if (euid == NANO_ROOT_UID)
683
684
	    SET(NO_WRAP);
#endif
Chris Allegretta's avatar
Chris Allegretta committed
685
686
	if ((rcstream = fopen(nanorc, "r")) == NULL) {
	    /* Don't complain about the file not existing */
687
	    if (errno != ENOENT) {
688
		rcfile_error(N_("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 */