blob: 8545526ba5dd87a868e777001c776f84528c706b [file] [log] [blame]
Chris Allegretta8d8e0122001-04-18 04:28:54 +00001/* $Id$ */
2/**************************************************************************
Chris Allegrettaa9434802001-05-05 15:02:27 +00003 * rcfile.c *
Chris Allegretta8d8e0122001-04-18 04:28:54 +00004 * *
Jordi Mallach8ae57892002-01-04 17:57:40 +00005 * Copyright (C) 1999-2002 Chris Allegretta *
Chris Allegretta8d8e0122001-04-18 04:28:54 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegretta8d8e0122001-04-18 04:28:54 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000022#include "config.h"
23
Chris Allegretta8d8e0122001-04-18 04:28:54 +000024#include <stdlib.h>
Chris Allegretta34f80982002-01-22 20:09:20 +000025#include <stdarg.h>
Chris Allegretta8d8e0122001-04-18 04:28:54 +000026#include <string.h>
27#include <stdio.h>
28#include <errno.h>
Chris Allegretta4dc03d52002-05-11 03:04:44 +000029#include <unistd.h>
30#include <pwd.h>
Chris Allegretta8d8e0122001-04-18 04:28:54 +000031#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
Chris Allegretta6df90f52002-07-19 01:08:59 +000034#include <assert.h>
Chris Allegretta8d8e0122001-04-18 04:28:54 +000035#include "proto.h"
36#include "nano.h"
37
38#ifdef ENABLE_NANORC
39
Chris Allegretta6232d662002-05-12 19:52:15 +000040#ifdef ENABLE_NLS
Chris Allegretta8d8e0122001-04-18 04:28:54 +000041#include <libintl.h>
42#define _(string) gettext(string)
43#else
44#define _(string) (string)
45#endif
46
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000047const static rcoption rcopts[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000048#ifndef NANO_SMALL
Chris Allegretta6c1e6612002-01-19 16:52:34 +000049 {"autoindent", AUTOINDENT},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000050 {"backup", BACKUP_FILE},
51#endif
52 {"const", CONSTUPDATE},
53#ifndef NANO_SMALL
Chris Allegretta6c1e6612002-01-19 16:52:34 +000054 {"cut", CUT_TO_END},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000055#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +000056#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6c1e6612002-01-19 16:52:34 +000057 {"fill", 0},
Chris Allegretta6df90f52002-07-19 01:08:59 +000058#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000059 {"keypad", ALT_KEYPAD},
60#ifndef DISABLE_MOUSE
61 {"mouse", USE_MOUSE},
62#endif
63#ifdef ENABLE_MULTIBUFFER
64 {"multibuffer", MULTIBUFFER},
65#endif
66#ifndef NANO_SMALL
67 {"noconvert", NO_CONVERT},
68#endif
69 {"nofollow", FOLLOW_SYMLINKS},
70 {"nohelp", NO_HELP},
Chris Allegretta6df90f52002-07-19 01:08:59 +000071#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000072 {"nowrap", NO_WRAP},
Chris Allegretta6df90f52002-07-19 01:08:59 +000073#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000074#ifndef DISABLE_OPERATINGDIR
75 {"operatingdir", 0},
76#endif
77 {"pico", PICO_MODE},
78#ifndef NANO_SMALL
79 {"quotestr", 0},
80#endif
81#ifdef HAVE_REGEX_H
82 {"regexp", USE_REGEXP},
83#endif
84#ifndef NANO_SMALL
85 {"smooth", SMOOTHSCROLL},
86#endif
87#ifndef DISABLE_SPELLER
Chris Allegretta6c1e6612002-01-19 16:52:34 +000088 {"speller", 0},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000089#endif
90 {"suspend", SUSPEND},
91 {"tabsize", 0},
Chris Allegretta6c1e6612002-01-19 16:52:34 +000092 {"tempfile", TEMP_OPT},
93 {"view", VIEW_MODE},
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000094 {NULL, 0}
Chris Allegretta6c1e6612002-01-19 16:52:34 +000095};
Chris Allegretta8d8e0122001-04-18 04:28:54 +000096
Chris Allegrettaf478f832002-01-18 21:54:35 +000097static int errors = 0;
98static int lineno = 0;
99static char *nanorc;
100
Chris Allegretta88520c92001-05-05 17:45:54 +0000101/* We have an error in some part of the rcfile; put it on stderr and
Chris Allegretta6df90f52002-07-19 01:08:59 +0000102 make the user hit return to continue starting up nano. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000103void rcfile_error(const char *msg, ...)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000104{
105 va_list ap;
106
107 fprintf(stderr, "\n");
Chris Allegretta78f0fc62002-03-29 19:41:57 +0000108 if (lineno > 0)
109 fprintf(stderr, _("Error in %s on line %d: "), nanorc, lineno);
110
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000111 va_start(ap, msg);
112 vfprintf(stderr, msg, ap);
113 va_end(ap);
114 fprintf(stderr, _("\nPress return to continue starting nano\n"));
115
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000116 while (getchar() != '\n');
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000117}
118
Chris Allegretta6df90f52002-07-19 01:08:59 +0000119/* Just print the error (one of many, perhaps) but don't abort, yet. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000120void rcfile_msg(const char *msg, ...)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000121{
122 va_list ap;
123
Chris Allegrettaf478f832002-01-18 21:54:35 +0000124 if (!errors) {
125 errors = 1;
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000126 fprintf(stderr, "\n");
127 }
128 va_start(ap, msg);
129 vfprintf(stderr, msg, ap);
130 va_end(ap);
131 fprintf(stderr, "\n");
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000132}
133
Chris Allegretta6df90f52002-07-19 01:08:59 +0000134/* Parse the next word from the string. Returns NULL if we hit EOL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000135char *parse_next_word(char *ptr)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000136{
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000137 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n' && *ptr != '\0')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000138 ptr++;
139
Chris Allegretta13fd44b2002-01-02 13:59:11 +0000140 if (*ptr == '\0')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000141 return NULL;
Chris Allegrettaf478f832002-01-18 21:54:35 +0000142
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000143 /* Null terminate and advance ptr */
144 *ptr++ = 0;
145
Chris Allegretta6df90f52002-07-19 01:08:59 +0000146 while (*ptr == ' ' || *ptr == '\t')
Chris Allegretta08893e02001-11-29 02:42:27 +0000147 ptr++;
148
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000149 return ptr;
150}
151
Chris Allegretta6df90f52002-07-19 01:08:59 +0000152/* The keywords operatingdir, fill, tabsize, speller, and quotestr take
153 * an argument when set. Among these, operatingdir, speller, and
154 * quotestr have to allow tabs and spaces in the argument. Thus, if the
155 * next word starts with a ", we say it ends with the last " of the line.
156 * Otherwise, the word is interpreted as usual. That is so the arguments
157 * can contain "s too. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000158char *parse_argument(char *ptr)
159{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000160 const char *ptr_bak = ptr;
161 char *last_quote = NULL;
162
163 assert(ptr != NULL);
164
165 if (*ptr != '"')
166 return parse_next_word(ptr);
167
168 do {
169 ptr++;
170 if (*ptr == '"')
171 last_quote = ptr;
172 } while (*ptr != '\n' && *ptr != '\0');
173
174 if (last_quote == NULL) {
175 if (*ptr == '\0')
176 ptr = NULL;
177 else
178 *ptr++ = '\0';
179 rcfile_error(_("argument %s has unterminated \""), ptr_bak);
180 } else {
181 *last_quote = '\0';
182 ptr = last_quote + 1;
183 }
184 if (ptr != NULL)
185 while (*ptr == ' ' || *ptr == '\t')
186 ptr++;
187 return ptr;
188}
189
190#ifdef ENABLE_COLOR
191
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000192int colortoint(const char *colorname, int *bright)
Chris Allegretta08893e02001-11-29 02:42:27 +0000193{
194 int mcolor = 0;
195
196 if (colorname == NULL)
197 return -1;
198
Chris Allegretta6df90f52002-07-19 01:08:59 +0000199 if (!strncasecmp(colorname, "bright", 6)) {
Chris Allegretta2fa11b82001-12-02 04:55:44 +0000200 *bright = 1;
Chris Allegretta08893e02001-11-29 02:42:27 +0000201 colorname += 6;
202 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000203
Chris Allegretta08893e02001-11-29 02:42:27 +0000204 if (!strcasecmp(colorname, "green"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000205 mcolor = COLOR_GREEN;
Chris Allegretta08893e02001-11-29 02:42:27 +0000206 else if (!strcasecmp(colorname, "red"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000207 mcolor = COLOR_RED;
Chris Allegretta08893e02001-11-29 02:42:27 +0000208 else if (!strcasecmp(colorname, "blue"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000209 mcolor = COLOR_BLUE;
Chris Allegretta08893e02001-11-29 02:42:27 +0000210 else if (!strcasecmp(colorname, "white"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000211 mcolor = COLOR_WHITE;
Chris Allegretta08893e02001-11-29 02:42:27 +0000212 else if (!strcasecmp(colorname, "yellow"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000213 mcolor = COLOR_YELLOW;
Chris Allegretta08893e02001-11-29 02:42:27 +0000214 else if (!strcasecmp(colorname, "cyan"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000215 mcolor = COLOR_CYAN;
Chris Allegretta08893e02001-11-29 02:42:27 +0000216 else if (!strcasecmp(colorname, "magenta"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000217 mcolor = COLOR_MAGENTA;
Chris Allegretta08893e02001-11-29 02:42:27 +0000218 else if (!strcasecmp(colorname, "black"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000219 mcolor = COLOR_BLACK;
Chris Allegretta08893e02001-11-29 02:42:27 +0000220 else {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000221 rcfile_error(_("color %s not understood.\n"
222 "Valid colors are \"green\", \"red\", \"blue\", \n"
223 "\"white\", \"yellow\", \"cyan\", \"magenta\" and \n"
224 "\"black\", with the optional prefix \"bright\".\n"));
Chris Allegretta08893e02001-11-29 02:42:27 +0000225 exit(1);
226 }
227
228 return mcolor;
229}
230
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000231char *parse_next_regex(char *ptr)
232{
233 while ((*ptr != '"' || (*(ptr + 1) != ' ' && *(ptr + 1) != '\n'))
234 && *ptr != '\n' && *ptr != '\0')
235 ptr++;
236
237 if (*ptr == '\0')
238 return NULL;
239
240 /* Null terminate and advance ptr */
241 *ptr++ = '\0';
242
243 while (*ptr == ' ' || *ptr == '\t')
244 ptr++;
245
246 return ptr;
247}
248
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000249void parse_syntax(char *ptr)
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000250{
251 syntaxtype *tmpsyntax = NULL;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000252 const char *fileregptr = NULL, *nameptr = NULL;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000253 exttype *exttmp = NULL;
254
255 while (*ptr == ' ')
256 ptr++;
257
258 if (*ptr == '\n' || *ptr == '\0')
259 return;
260
261 if (*ptr != '"') {
262 rcfile_error(_("regex strings must begin and end with a \" character\n"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000263 return;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000264 }
265 ptr++;
266
267 nameptr = ptr;
268 ptr = parse_next_regex(ptr);
269
270 if (ptr == NULL) {
271 rcfile_error(_("Missing syntax name"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000272 return;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000273 }
274
Chris Allegretta6df90f52002-07-19 01:08:59 +0000275 if (syntaxes == NULL) {
276 syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype));
277 tmpsyntax = syntaxes;
278 } else {
279 for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
280 tmpsyntax = tmpsyntax->next)
281 ;
282 tmpsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype));
283 tmpsyntax = tmpsyntax->next;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000284#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000285 fprintf(stderr, _("Adding new syntax after 1st\n"));
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000286#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000287 }
288 tmpsyntax->desc = mallocstrcpy(NULL, nameptr);
289 tmpsyntax->color = NULL;
290 tmpsyntax->extensions = NULL;
291 tmpsyntax->next = NULL;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000292#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000293 fprintf(stderr, _("Starting a new syntax type\n"));
294 fprintf(stderr, "string val=%s\n", nameptr);
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000295#endif
296
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000297 /* Now load in the extensions to their part of the struct */
298 while (*ptr != '\n' && *ptr != '\0') {
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000299 while (*ptr != '"' && *ptr != '\n' && *ptr != '\0')
300 ptr++;
301
302 if (*ptr == '\n' || *ptr == '\0')
303 return;
304 ptr++;
305
306 fileregptr = ptr;
307 ptr = parse_next_regex(ptr);
308
309 if (tmpsyntax->extensions == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000310 tmpsyntax->extensions = (exttype *)nmalloc(sizeof(exttype));
311 exttmp = tmpsyntax->extensions;
312 } else {
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000313 for (exttmp = tmpsyntax->extensions; exttmp->next != NULL;
314 exttmp = exttmp->next);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000315 exttmp->next = (exttype *)nmalloc(sizeof(exttype));
316 exttmp = exttmp->next;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000317 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000318 exttmp->val = mallocstrcpy(NULL, fileregptr);
319 exttmp->next = NULL;
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000320 }
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000321}
322
Chris Allegretta08893e02001-11-29 02:42:27 +0000323/* Parse the color stuff into the colorstrings array */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000324void parse_colors(char *ptr)
Chris Allegretta08893e02001-11-29 02:42:27 +0000325{
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000326 int fg, bg, bright = 0;
327 int expectend = 0; /* Do we expect an end= line? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000328 char *fgstr;
Chris Allegretta08893e02001-11-29 02:42:27 +0000329 colortype *tmpcolor = NULL;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000330 syntaxtype *tmpsyntax = NULL;
Chris Allegretta08893e02001-11-29 02:42:27 +0000331
332 fgstr = ptr;
333 ptr = parse_next_word(ptr);
334
335 if (ptr == NULL) {
Chris Allegrettaf478f832002-01-18 21:54:35 +0000336 rcfile_error(_("Missing color name"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000337 return;
Chris Allegretta08893e02001-11-29 02:42:27 +0000338 }
339
340 if (strstr(fgstr, ",")) {
341 strtok(fgstr, ",");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000342 bg = colortoint(strtok(NULL, ","), &bright);
Chris Allegretta08893e02001-11-29 02:42:27 +0000343 } else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000344 bg = -1;
Chris Allegretta08893e02001-11-29 02:42:27 +0000345
Chris Allegrettaf478f832002-01-18 21:54:35 +0000346 fg = colortoint(fgstr, &bright);
Chris Allegretta08893e02001-11-29 02:42:27 +0000347
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000348 if (syntaxes == NULL) {
349 rcfile_error(_("Cannot add a color directive without a syntax line"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000350 return;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000351 }
352
353 for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
354 tmpsyntax = tmpsyntax->next)
355 ;
356
Chris Allegretta08893e02001-11-29 02:42:27 +0000357 /* Now the fun part, start adding regexps to individual strings
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000358 in the colorstrings array, woo! */
Chris Allegretta08893e02001-11-29 02:42:27 +0000359
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000360 while (*ptr != '\0') {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000361 while (*ptr == ' ')
Chris Allegretta08893e02001-11-29 02:42:27 +0000362 ptr++;
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000363
364 if (*ptr == '\n' || *ptr == '\0')
Chris Allegretta08893e02001-11-29 02:42:27 +0000365 break;
Chris Allegretta08893e02001-11-29 02:42:27 +0000366
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000367 if (!strncasecmp(ptr, "start=", 6)) {
368 ptr += 6;
369 expectend = 1;
Chris Allegrettaf478f832002-01-18 21:54:35 +0000370 }
371
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000372 if (*ptr != '"') {
373 rcfile_error(_("regex strings must begin and end with a \" character\n"));
374 continue;
375 }
376 ptr++;
377
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000378 if (tmpsyntax->color == NULL) {
379 tmpsyntax->color = nmalloc(sizeof(colortype));
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000380 tmpcolor = tmpsyntax->color;
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000381#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000382 fprintf(stderr, _("Starting a new colorstring for fg %d bg %d\n"),
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000383 fg, bg);
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000384#endif
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000385 } else {
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000386 for (tmpcolor = tmpsyntax->color;
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000387 tmpcolor->next != NULL; tmpcolor = tmpcolor->next);
388#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000389 fprintf(stderr, _("Adding new entry for fg %d bg %d\n"), fg, bg);
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000390#endif
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000391 tmpcolor->next = nmalloc(sizeof(colortype));
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000392 tmpcolor = tmpcolor->next;
393 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000394 tmpcolor->fg = fg;
395 tmpcolor->bg = bg;
396 tmpcolor->bright = bright;
397 tmpcolor->next = NULL;
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000398
Chris Allegretta6df90f52002-07-19 01:08:59 +0000399 tmpcolor->start = ptr;
400 ptr = parse_next_regex(ptr);
401 tmpcolor->start = mallocstrcpy(NULL, tmpcolor->start);
402#ifdef DEBUG
403 fprintf(stderr, _("string val=%s\n"), tmpcolor->start);
404#endif
405
406 if (!expectend)
407 tmpcolor->end = NULL;
408 else {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000409 if (ptr == NULL || strncasecmp(ptr, "end=", 4)) {
410 rcfile_error(_
411 ("\n\t\"start=\" requires a corresponding \"end=\""));
412 return;
413 }
414
415 ptr += 4;
416
417 if (*ptr != '"') {
418 rcfile_error(_
419 ("regex strings must begin and end with a \" character\n"));
420 continue;
421 }
422 ptr++;
423
Chris Allegretta6df90f52002-07-19 01:08:59 +0000424 tmpcolor->end = ptr;
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000425 ptr = parse_next_regex(ptr);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000426 tmpcolor->end = mallocstrcpy(NULL, tmpcolor->end);
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000427#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000428 fprintf(stderr, _("For end part, beginning = \"%s\"\n"),
Chris Allegretta6df90f52002-07-19 01:08:59 +0000429 tmpcolor->end);
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000430#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000431 }
Chris Allegrettaf478f832002-01-18 21:54:35 +0000432 }
Chris Allegretta08893e02001-11-29 02:42:27 +0000433}
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000434
435#endif /* ENABLE_COLOR */
Chris Allegretta08893e02001-11-29 02:42:27 +0000436
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000437/* Parse the RC file, once it has been opened successfully */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000438void parse_rcfile(FILE *rcstream)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000439{
440 char *buf, *ptr, *keyword, *option;
Chris Allegretta1596d382002-03-07 00:46:17 +0000441 int set = 0, i, j;
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000442
Chris Allegretta8d848af2001-05-18 04:44:16 +0000443 buf = charalloc(1024);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000444 while (fgets(buf, 1023, rcstream) != 0) {
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000445 lineno++;
446 ptr = buf;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000447 while (*ptr == ' ' || *ptr == '\t')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000448 ptr++;
449
450 if (*ptr == '\n' || *ptr == '\0')
451 continue;
452
453 if (*ptr == '#') {
454#ifdef DEBUG
455 fprintf(stderr, _("parse_rcfile: Read a comment\n"));
456#endif
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000457 continue; /* Skip past commented lines */
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000458 }
459
460 /* Else skip to the next space */
461 keyword = ptr;
462 ptr = parse_next_word(ptr);
463 if (!ptr)
464 continue;
465
466 /* Else try to parse the keyword */
467 if (!strcasecmp(keyword, "set"))
468 set = 1;
469 else if (!strcasecmp(keyword, "unset"))
470 set = -1;
Chris Allegretta08893e02001-11-29 02:42:27 +0000471#ifdef ENABLE_COLOR
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000472 else if (!strcasecmp(keyword, "syntax"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000473 parse_syntax(ptr);
Chris Allegretta08893e02001-11-29 02:42:27 +0000474 else if (!strcasecmp(keyword, "color"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000475 parse_colors(ptr);
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000476#endif /* ENABLE_COLOR */
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000477 else {
Chris Allegrettaf478f832002-01-18 21:54:35 +0000478 rcfile_msg(_("command %s not understood"), keyword);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000479 continue;
480 }
481
482 option = ptr;
483 ptr = parse_next_word(ptr);
484 /* We don't care if ptr == NULL, as it should if using proper syntax */
485
486 if (set != 0) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +0000487 for (i = 0; rcopts[i].name != NULL; i++) {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000488 if (!strcasecmp(option, rcopts[i].name)) {
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000489#ifdef DEBUG
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000490 fprintf(stderr, _("parse_rcfile: Parsing option %s\n"),
491 rcopts[i].name);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000492#endif
493 if (set == 1 || rcopts[i].flag == FOLLOW_SYMLINKS) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000494 if (!strcasecmp(rcopts[i].name, "tabsize")
495#ifndef DISABLE_OPERATINGDIR
496 || !strcasecmp(rcopts[i].name, "operatingdir")
497#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +0000498#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000499 || !strcasecmp(rcopts[i].name, "fill")
Chris Allegretta6fe61492001-05-21 12:56:25 +0000500#endif
Chris Allegrettad76ca2b2002-03-03 22:52:52 +0000501#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000502 || !strcasecmp(rcopts[i].name, "quotestr")
Chris Allegrettad76ca2b2002-03-03 22:52:52 +0000503#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +0000504#ifndef DISABLE_SPELLER
Chris Allegretta6df90f52002-07-19 01:08:59 +0000505 || !strcasecmp(rcopts[i].name, "speller")
Chris Allegretta6fe61492001-05-21 12:56:25 +0000506#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000507 ) {
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000508 if (*ptr == '\n' || *ptr == '\0') {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000509 rcfile_error(_
510 ("option %s requires an argument"),
511 rcopts[i].name);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000512 continue;
513 }
514 option = ptr;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000515 if (*option == '"')
516 option++;
517 ptr = parse_argument(ptr);
518#ifdef DEBUG
519 fprintf(stderr, "option = %s\n", option);
520#endif
521#ifndef DISABLE_OPERATINGDIR
522 if (!strcasecmp(rcopts[i].name, "operatingdir"))
523 operating_dir = mallocstrcpy(NULL, option);
524 else
525#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +0000526#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000527 if (!strcasecmp(rcopts[i].name, "fill")) {
528 char *first_error;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000529
Chris Allegretta6df90f52002-07-19 01:08:59 +0000530 /* Using strtol instead of atoi lets us
531 * accept 0 while checking other
532 * errors. */
533 j = (int)strtol(option, &first_error, 10);
534 if (errno == ERANGE || *option == '\0' || *first_error != '\0')
535 rcfile_error(_("requested fill size %d invalid"),
Chris Allegretta1596d382002-03-07 00:46:17 +0000536 j);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000537 else
538 wrap_at = j;
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000539 } else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000540#endif
Chris Allegrettad76ca2b2002-03-03 22:52:52 +0000541#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000542 if (!strcasecmp(rcopts[i].name, "quotestr"))
543 quotestr = mallocstrcpy(NULL, option);
544 else
Chris Allegrettad76ca2b2002-03-03 22:52:52 +0000545#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +0000546#ifndef DISABLE_SPELLER
Chris Allegretta6df90f52002-07-19 01:08:59 +0000547 if (!strcasecmp(rcopts[i].name, "speller"))
548 alt_speller = mallocstrcpy(NULL, option);
549 else
Chris Allegretta6fe61492001-05-21 12:56:25 +0000550#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000551 {
552 char *first_error;
553
554 /* Using strtol instead of atoi lets us
555 * accept 0 while checking other
556 * errors. */
557 j = (int)strtol(option, &first_error, 10);
558 if (errno == ERANGE || *option == '\0' || *first_error != '\0')
559 rcfile_error(_("requested tab size %d invalid"),
560 j);
561 else
562 tabsize = j;
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000563 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000564 } else
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000565 SET(rcopts[i].flag);
566#ifdef DEBUG
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000567 fprintf(stderr, _("set flag %d!\n"),
568 rcopts[i].flag);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000569#endif
570 } else {
571 UNSET(rcopts[i].flag);
572#ifdef DEBUG
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000573 fprintf(stderr, _("unset flag %d!\n"),
574 rcopts[i].flag);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000575#endif
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000576 }
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000577 }
578 }
579 }
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000580 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000581 free(buf);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000582 if (errors)
583 rcfile_error(_("Errors found in .nanorc file"));
584
585 return;
586}
587
588/* The main rc file function, tries to open the rc file */
589void do_rcfile(void)
590{
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000591 FILE *rcstream;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000592 const struct passwd *userage;
593 uid_t euid = geteuid();
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000594
Chris Allegretta6df90f52002-07-19 01:08:59 +0000595#ifdef SYSCONFDIR
596 assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
597 nanorc = charalloc(sizeof(SYSCONFDIR) + 7);
Chris Allegrettaff8a68c2002-02-16 20:34:57 +0000598 sprintf(nanorc, "%s/nanorc", SYSCONFDIR);
Chris Allegrettaff8a68c2002-02-16 20:34:57 +0000599 /* Try to open system nanorc */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000600 if ((rcstream = fopen(nanorc, "r")) != NULL) {
601 /* Parse it! */
602 parse_rcfile(rcstream);
603 fclose(rcstream);
604 }
605#endif
Chris Allegrettaff8a68c2002-02-16 20:34:57 +0000606
Chris Allegretta6df90f52002-07-19 01:08:59 +0000607 /* Determine home directory using getpwent(), don't rely on $HOME */
608 do {
609 userage = getpwent();
610 } while (userage != NULL && userage->pw_uid != euid);
611 endpwent();
Chris Allegrettaff8a68c2002-02-16 20:34:57 +0000612
Chris Allegretta78f0fc62002-03-29 19:41:57 +0000613 lineno = 0;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000614
Chris Allegretta6df90f52002-07-19 01:08:59 +0000615 if (userage == NULL)
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000616 rcfile_error(_("I can't find my home directory! Wah!"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000617 else {
618 nanorc = nrealloc(nanorc, strlen(userage->pw_dir) + 9);
619 sprintf(nanorc, "%s/.nanorc", userage->pw_dir);
620
621 if ((rcstream = fopen(nanorc, "r")) == NULL) {
622 /* Don't complain about the file not existing */
623 if (errno != ENOENT)
624 rcfile_error(_("Unable to open ~/.nanorc file, %s"),
625 strerror(errno));
626 } else {
627 parse_rcfile(rcstream);
628 fclose(rcstream);
629 }
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000630 }
631
Chris Allegretta6df90f52002-07-19 01:08:59 +0000632 free(nanorc);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000633}
634
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000635#endif /* ENABLE_NANORC */