blob: 03f5dfeede70eb572158258b498d516aec106272 [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 * *
Chris Allegrettad757e252003-01-15 19:33:27 +00005 * Copyright (C) 1999-2003 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>
Chris Allegretta8d8e0122001-04-18 04:28:54 +000030#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
Chris Allegretta7662c862003-01-13 01:35:15 +000033#include <pwd.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
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000040const static rcoption rcopts[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000041#ifndef NANO_SMALL
Chris Allegretta6c1e6612002-01-19 16:52:34 +000042 {"autoindent", AUTOINDENT},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000043 {"backup", BACKUP_FILE},
44#endif
45 {"const", CONSTUPDATE},
46#ifndef NANO_SMALL
Chris Allegretta6c1e6612002-01-19 16:52:34 +000047 {"cut", CUT_TO_END},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000048#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +000049#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6c1e6612002-01-19 16:52:34 +000050 {"fill", 0},
Chris Allegretta6df90f52002-07-19 01:08:59 +000051#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000052 {"keypad", ALT_KEYPAD},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +000053#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000054 {"mouse", USE_MOUSE},
55#endif
56#ifdef ENABLE_MULTIBUFFER
57 {"multibuffer", MULTIBUFFER},
58#endif
59#ifndef NANO_SMALL
60 {"noconvert", NO_CONVERT},
61#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +000062 {"nofollow", NOFOLLOW_SYMLINKS},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000063 {"nohelp", NO_HELP},
Chris Allegretta6df90f52002-07-19 01:08:59 +000064#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000065 {"nowrap", NO_WRAP},
Chris Allegretta6df90f52002-07-19 01:08:59 +000066#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000067#ifndef DISABLE_OPERATINGDIR
68 {"operatingdir", 0},
69#endif
Chris Allegretta7662c862003-01-13 01:35:15 +000070 {"preserve", PRESERVE},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +000071#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000072 {"quotestr", 0},
73#endif
74#ifdef HAVE_REGEX_H
75 {"regexp", USE_REGEXP},
76#endif
77#ifndef NANO_SMALL
78 {"smooth", SMOOTHSCROLL},
79#endif
80#ifndef DISABLE_SPELLER
Chris Allegretta6c1e6612002-01-19 16:52:34 +000081 {"speller", 0},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +000082#endif
83 {"suspend", SUSPEND},
84 {"tabsize", 0},
Chris Allegretta6c1e6612002-01-19 16:52:34 +000085 {"tempfile", TEMP_OPT},
86 {"view", VIEW_MODE},
Chris Allegrettaf3de8b52003-01-16 23:44:46 +000087 {"historylog", HISTORYLOG},
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000088 {NULL, 0}
Chris Allegretta6c1e6612002-01-19 16:52:34 +000089};
Chris Allegretta8d8e0122001-04-18 04:28:54 +000090
Chris Allegrettaf478f832002-01-18 21:54:35 +000091static int errors = 0;
92static int lineno = 0;
93static char *nanorc;
94
Chris Allegretta88520c92001-05-05 17:45:54 +000095/* We have an error in some part of the rcfile; put it on stderr and
Chris Allegretta6df90f52002-07-19 01:08:59 +000096 make the user hit return to continue starting up nano. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +000097void rcfile_error(const char *msg, ...)
Chris Allegretta8d8e0122001-04-18 04:28:54 +000098{
99 va_list ap;
100
101 fprintf(stderr, "\n");
Chris Allegretta78f0fc62002-03-29 19:41:57 +0000102 if (lineno > 0)
103 fprintf(stderr, _("Error in %s on line %d: "), nanorc, lineno);
104
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000105 va_start(ap, msg);
106 vfprintf(stderr, msg, ap);
107 va_end(ap);
108 fprintf(stderr, _("\nPress return to continue starting nano\n"));
109
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000110 while (getchar() != '\n');
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000111}
112
Chris Allegretta6df90f52002-07-19 01:08:59 +0000113/* Just print the error (one of many, perhaps) but don't abort, yet. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000114void rcfile_msg(const char *msg, ...)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000115{
116 va_list ap;
117
Chris Allegrettaf478f832002-01-18 21:54:35 +0000118 if (!errors) {
119 errors = 1;
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000120 fprintf(stderr, "\n");
121 }
122 va_start(ap, msg);
123 vfprintf(stderr, msg, ap);
124 va_end(ap);
125 fprintf(stderr, "\n");
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000126}
127
Chris Allegretta6df90f52002-07-19 01:08:59 +0000128/* Parse the next word from the string. Returns NULL if we hit EOL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000129char *parse_next_word(char *ptr)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000130{
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000131 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n' && *ptr != '\0')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000132 ptr++;
133
Chris Allegretta13fd44b2002-01-02 13:59:11 +0000134 if (*ptr == '\0')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000135 return NULL;
Chris Allegrettaf478f832002-01-18 21:54:35 +0000136
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000137 /* Null terminate and advance ptr */
138 *ptr++ = 0;
139
Chris Allegretta6df90f52002-07-19 01:08:59 +0000140 while (*ptr == ' ' || *ptr == '\t')
Chris Allegretta08893e02001-11-29 02:42:27 +0000141 ptr++;
142
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000143 return ptr;
144}
145
Chris Allegretta6df90f52002-07-19 01:08:59 +0000146/* The keywords operatingdir, fill, tabsize, speller, and quotestr take
147 * an argument when set. Among these, operatingdir, speller, and
148 * quotestr have to allow tabs and spaces in the argument. Thus, if the
149 * next word starts with a ", we say it ends with the last " of the line.
150 * Otherwise, the word is interpreted as usual. That is so the arguments
151 * can contain "s too. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000152char *parse_argument(char *ptr)
153{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000154 const char *ptr_bak = ptr;
155 char *last_quote = NULL;
156
157 assert(ptr != NULL);
158
159 if (*ptr != '"')
160 return parse_next_word(ptr);
161
162 do {
163 ptr++;
164 if (*ptr == '"')
165 last_quote = ptr;
166 } while (*ptr != '\n' && *ptr != '\0');
167
168 if (last_quote == NULL) {
169 if (*ptr == '\0')
170 ptr = NULL;
171 else
172 *ptr++ = '\0';
173 rcfile_error(_("argument %s has unterminated \""), ptr_bak);
174 } else {
175 *last_quote = '\0';
176 ptr = last_quote + 1;
177 }
178 if (ptr != NULL)
179 while (*ptr == ' ' || *ptr == '\t')
180 ptr++;
181 return ptr;
182}
183
184#ifdef ENABLE_COLOR
185
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000186int colortoint(const char *colorname, int *bright)
Chris Allegretta08893e02001-11-29 02:42:27 +0000187{
188 int mcolor = 0;
189
190 if (colorname == NULL)
191 return -1;
192
Chris Allegretta6df90f52002-07-19 01:08:59 +0000193 if (!strncasecmp(colorname, "bright", 6)) {
Chris Allegretta2fa11b82001-12-02 04:55:44 +0000194 *bright = 1;
Chris Allegretta08893e02001-11-29 02:42:27 +0000195 colorname += 6;
196 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000197
Chris Allegretta08893e02001-11-29 02:42:27 +0000198 if (!strcasecmp(colorname, "green"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000199 mcolor = COLOR_GREEN;
Chris Allegretta08893e02001-11-29 02:42:27 +0000200 else if (!strcasecmp(colorname, "red"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000201 mcolor = COLOR_RED;
Chris Allegretta08893e02001-11-29 02:42:27 +0000202 else if (!strcasecmp(colorname, "blue"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000203 mcolor = COLOR_BLUE;
Chris Allegretta08893e02001-11-29 02:42:27 +0000204 else if (!strcasecmp(colorname, "white"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000205 mcolor = COLOR_WHITE;
Chris Allegretta08893e02001-11-29 02:42:27 +0000206 else if (!strcasecmp(colorname, "yellow"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000207 mcolor = COLOR_YELLOW;
Chris Allegretta08893e02001-11-29 02:42:27 +0000208 else if (!strcasecmp(colorname, "cyan"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000209 mcolor = COLOR_CYAN;
Chris Allegretta08893e02001-11-29 02:42:27 +0000210 else if (!strcasecmp(colorname, "magenta"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000211 mcolor = COLOR_MAGENTA;
Chris Allegretta08893e02001-11-29 02:42:27 +0000212 else if (!strcasecmp(colorname, "black"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000213 mcolor = COLOR_BLACK;
Chris Allegretta08893e02001-11-29 02:42:27 +0000214 else {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000215 rcfile_error(_("color %s not understood.\n"
216 "Valid colors are \"green\", \"red\", \"blue\", \n"
217 "\"white\", \"yellow\", \"cyan\", \"magenta\" and \n"
Chris Allegrettad6e84362003-02-07 00:02:00 +0000218 "\"black\", with the optional prefix \"bright\".\n"),
219 colorname);
220 mcolor = -1;
Chris Allegretta08893e02001-11-29 02:42:27 +0000221 }
Chris Allegretta08893e02001-11-29 02:42:27 +0000222 return mcolor;
223}
224
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000225char *parse_next_regex(char *ptr)
226{
227 while ((*ptr != '"' || (*(ptr + 1) != ' ' && *(ptr + 1) != '\n'))
228 && *ptr != '\n' && *ptr != '\0')
229 ptr++;
230
231 if (*ptr == '\0')
232 return NULL;
233
234 /* Null terminate and advance ptr */
235 *ptr++ = '\0';
236
237 while (*ptr == ' ' || *ptr == '\t')
238 ptr++;
239
240 return ptr;
241}
242
Chris Allegrettace452fb2003-02-03 02:56:44 +0000243/* Compile the regular expression regex to preg. Returns FALSE on success,
244 TRUE if the expression is invalid. */
245int nregcomp(regex_t *preg, const char *regex, int flags)
246{
247 int rc = regcomp(preg, regex, REG_EXTENDED | flags);
248
249 if (rc != 0) {
250 size_t len = regerror(rc, preg, NULL, 0);
251 char *str = charalloc(len);
252
253 regerror(rc, preg, str, len);
254 rcfile_error(_("Bad regex \"%s\": %s"), regex, str);
255 free(str);
256 }
257 return rc != 0;
258}
259
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000260void parse_syntax(char *ptr)
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000261{
262 syntaxtype *tmpsyntax = NULL;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000263 const char *fileregptr = NULL, *nameptr = NULL;
Chris Allegrettace452fb2003-02-03 02:56:44 +0000264 exttype *endext = NULL;
265 /* The end of the extensions list for this syntax. */
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000266
267 while (*ptr == ' ')
268 ptr++;
269
270 if (*ptr == '\n' || *ptr == '\0')
271 return;
272
273 if (*ptr != '"') {
274 rcfile_error(_("regex strings must begin and end with a \" character\n"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000275 return;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000276 }
277 ptr++;
278
279 nameptr = ptr;
280 ptr = parse_next_regex(ptr);
281
282 if (ptr == NULL) {
283 rcfile_error(_("Missing syntax name"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000284 return;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000285 }
286
Chris Allegretta6df90f52002-07-19 01:08:59 +0000287 if (syntaxes == NULL) {
288 syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype));
289 tmpsyntax = syntaxes;
Chris Allegretta1dd0bc92002-10-13 18:43:45 +0000290 SET(COLOR_SYNTAX);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000291 } else {
292 for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
293 tmpsyntax = tmpsyntax->next)
294 ;
295 tmpsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype));
296 tmpsyntax = tmpsyntax->next;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000297#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000298 fprintf(stderr, _("Adding new syntax after 1st\n"));
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000299#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000300 }
301 tmpsyntax->desc = mallocstrcpy(NULL, nameptr);
302 tmpsyntax->color = NULL;
303 tmpsyntax->extensions = NULL;
304 tmpsyntax->next = NULL;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000305#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000306 fprintf(stderr, _("Starting a new syntax type\n"));
307 fprintf(stderr, "string val=%s\n", nameptr);
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000308#endif
309
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000310 /* Now load in the extensions to their part of the struct */
311 while (*ptr != '\n' && *ptr != '\0') {
Chris Allegrettace452fb2003-02-03 02:56:44 +0000312 exttype *newext;
313 /* The new extension structure. */
314
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000315 while (*ptr != '"' && *ptr != '\n' && *ptr != '\0')
316 ptr++;
317
318 if (*ptr == '\n' || *ptr == '\0')
319 return;
320 ptr++;
321
322 fileregptr = ptr;
323 ptr = parse_next_regex(ptr);
324
Chris Allegrettace452fb2003-02-03 02:56:44 +0000325 newext = (exttype *)nmalloc(sizeof(exttype));
326 if (nregcomp(&newext->val, fileregptr, REG_NOSUB))
327 free(newext);
328 else {
329 if (endext == NULL)
330 tmpsyntax->extensions = newext;
331 else
332 endext->next = newext;
333 endext = newext;
334 endext->next = NULL;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000335 }
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000336 }
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000337}
338
Chris Allegretta08893e02001-11-29 02:42:27 +0000339/* Parse the color stuff into the colorstrings array */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000340void parse_colors(char *ptr)
Chris Allegretta08893e02001-11-29 02:42:27 +0000341{
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000342 int fg, bg, bright = 0;
343 int expectend = 0; /* Do we expect an end= line? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000344 char *fgstr;
Chris Allegretta08893e02001-11-29 02:42:27 +0000345 colortype *tmpcolor = NULL;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000346 syntaxtype *tmpsyntax = NULL;
Chris Allegretta08893e02001-11-29 02:42:27 +0000347
348 fgstr = ptr;
349 ptr = parse_next_word(ptr);
350
351 if (ptr == NULL) {
Chris Allegrettaf478f832002-01-18 21:54:35 +0000352 rcfile_error(_("Missing color name"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000353 return;
Chris Allegretta08893e02001-11-29 02:42:27 +0000354 }
355
356 if (strstr(fgstr, ",")) {
357 strtok(fgstr, ",");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000358 bg = colortoint(strtok(NULL, ","), &bright);
Chris Allegretta08893e02001-11-29 02:42:27 +0000359 } else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000360 bg = -1;
Chris Allegretta08893e02001-11-29 02:42:27 +0000361
Chris Allegrettaf478f832002-01-18 21:54:35 +0000362 fg = colortoint(fgstr, &bright);
Chris Allegretta08893e02001-11-29 02:42:27 +0000363
Chris Allegretta17ec14b2003-02-07 00:19:05 +0000364 /* Don't try and parse screwed up fg colors */
365 if (fg == -1)
366 return;
367
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000368 if (syntaxes == NULL) {
369 rcfile_error(_("Cannot add a color directive without a syntax line"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000370 return;
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000371 }
372
373 for (tmpsyntax = syntaxes; tmpsyntax->next != NULL;
374 tmpsyntax = tmpsyntax->next)
375 ;
376
Chris Allegretta08893e02001-11-29 02:42:27 +0000377 /* Now the fun part, start adding regexps to individual strings
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000378 in the colorstrings array, woo! */
Chris Allegretta08893e02001-11-29 02:42:27 +0000379
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000380 while (*ptr != '\0') {
Chris Allegrettace452fb2003-02-03 02:56:44 +0000381 colortype *newcolor;
382 /* The new color structure. */
383 int cancelled = 0;
384 /* The start expression was bad. */
385
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000386 while (*ptr == ' ')
Chris Allegretta08893e02001-11-29 02:42:27 +0000387 ptr++;
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000388
389 if (*ptr == '\n' || *ptr == '\0')
Chris Allegretta08893e02001-11-29 02:42:27 +0000390 break;
Chris Allegretta08893e02001-11-29 02:42:27 +0000391
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000392 if (!strncasecmp(ptr, "start=", 6)) {
393 ptr += 6;
394 expectend = 1;
Chris Allegrettaf478f832002-01-18 21:54:35 +0000395 }
396
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000397 if (*ptr != '"') {
398 rcfile_error(_("regex strings must begin and end with a \" character\n"));
Chris Allegrettade852622002-09-18 00:28:57 +0000399 ptr = parse_next_regex(ptr);
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000400 continue;
401 }
402 ptr++;
403
Chris Allegrettace452fb2003-02-03 02:56:44 +0000404 newcolor = (colortype *)nmalloc(sizeof(colortype));
405 fgstr = ptr;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000406 ptr = parse_next_regex(ptr);
Chris Allegrettace452fb2003-02-03 02:56:44 +0000407 if (nregcomp(&newcolor->start, fgstr, 0)) {
408 free(newcolor);
409 cancelled = 1;
410 } else {
411 newcolor->fg = fg;
412 newcolor->bg = bg;
413 newcolor->bright = bright;
414 newcolor->next = NULL;
415 newcolor->end = NULL;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000416
Chris Allegrettace452fb2003-02-03 02:56:44 +0000417 if (tmpsyntax->color == NULL) {
418 tmpsyntax->color = newcolor;
419#ifdef DEBUG
420 fprintf(stderr, _("Starting a new colorstring for fg %d bg %d\n"),
421 fg, bg);
422#endif
423 } else {
424 for (tmpcolor = tmpsyntax->color; tmpcolor->next != NULL;
425 tmpcolor = tmpcolor->next)
426 ;
427#ifdef DEBUG
428 fprintf(stderr, _("Adding new entry for fg %d bg %d\n"), fg, bg);
429#endif
430 tmpcolor->next = newcolor;
431 }
432 }
433
434 if (expectend) {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000435 if (ptr == NULL || strncasecmp(ptr, "end=", 4)) {
436 rcfile_error(_
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000437 ("\"start=\" requires a corresponding \"end=\""));
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000438 return;
439 }
440
441 ptr += 4;
442
443 if (*ptr != '"') {
444 rcfile_error(_
445 ("regex strings must begin and end with a \" character\n"));
446 continue;
447 }
448 ptr++;
449
Chris Allegrettace452fb2003-02-03 02:56:44 +0000450 fgstr = ptr;
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000451 ptr = parse_next_regex(ptr);
Chris Allegrettace452fb2003-02-03 02:56:44 +0000452
453 /* If the start regex was invalid, skip past the end regex to
454 * stay in sync. */
455 if (cancelled)
456 continue;
457 newcolor->end = (regex_t *)nmalloc(sizeof(regex_t));
458 if (nregcomp(newcolor->end, fgstr, 0)) {
459 free(newcolor->end);
460 newcolor->end = NULL;
461 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000462 }
Chris Allegrettaf478f832002-01-18 21:54:35 +0000463 }
Chris Allegretta08893e02001-11-29 02:42:27 +0000464}
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000465
466#endif /* ENABLE_COLOR */
Chris Allegretta08893e02001-11-29 02:42:27 +0000467
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000468/* Parse the RC file, once it has been opened successfully */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000469void parse_rcfile(FILE *rcstream)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000470{
471 char *buf, *ptr, *keyword, *option;
Chris Allegretta1596d382002-03-07 00:46:17 +0000472 int set = 0, i, j;
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000473
Chris Allegretta8d848af2001-05-18 04:44:16 +0000474 buf = charalloc(1024);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000475 while (fgets(buf, 1023, rcstream) != 0) {
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000476 lineno++;
477 ptr = buf;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000478 while (*ptr == ' ' || *ptr == '\t')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000479 ptr++;
480
481 if (*ptr == '\n' || *ptr == '\0')
482 continue;
483
484 if (*ptr == '#') {
485#ifdef DEBUG
Chris Allegretta0e86e602003-01-23 04:27:23 +0000486 fprintf(stderr, _("%s: Read a comment\n"), "parse_rcfile()");
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000487#endif
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000488 continue; /* Skip past commented lines */
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000489 }
490
491 /* Else skip to the next space */
492 keyword = ptr;
493 ptr = parse_next_word(ptr);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000494 if (ptr == NULL)
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000495 continue;
496
497 /* Else try to parse the keyword */
498 if (!strcasecmp(keyword, "set"))
499 set = 1;
500 else if (!strcasecmp(keyword, "unset"))
501 set = -1;
Chris Allegretta08893e02001-11-29 02:42:27 +0000502#ifdef ENABLE_COLOR
Chris Allegrettab6c5dc22002-05-04 03:47:33 +0000503 else if (!strcasecmp(keyword, "syntax"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000504 parse_syntax(ptr);
Chris Allegretta08893e02001-11-29 02:42:27 +0000505 else if (!strcasecmp(keyword, "color"))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000506 parse_colors(ptr);
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000507#endif /* ENABLE_COLOR */
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000508 else {
Chris Allegrettaf478f832002-01-18 21:54:35 +0000509 rcfile_msg(_("command %s not understood"), keyword);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000510 continue;
511 }
512
513 option = ptr;
514 ptr = parse_next_word(ptr);
515 /* We don't care if ptr == NULL, as it should if using proper syntax */
516
517 if (set != 0) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +0000518 for (i = 0; rcopts[i].name != NULL; i++) {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000519 if (!strcasecmp(option, rcopts[i].name)) {
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000520#ifdef DEBUG
Chris Allegretta0e86e602003-01-23 04:27:23 +0000521 fprintf(stderr, _("%s: Parsing option %s\n"),
522 "parse_rcfile()", rcopts[i].name);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000523#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000524 if (set == 1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000525 if (!strcasecmp(rcopts[i].name, "tabsize")
526#ifndef DISABLE_OPERATINGDIR
527 || !strcasecmp(rcopts[i].name, "operatingdir")
528#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +0000529#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000530 || !strcasecmp(rcopts[i].name, "fill")
Chris Allegretta6fe61492001-05-21 12:56:25 +0000531#endif
Chris Allegrettad76ca2b2002-03-03 22:52:52 +0000532#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000533 || !strcasecmp(rcopts[i].name, "quotestr")
Chris Allegrettad76ca2b2002-03-03 22:52:52 +0000534#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +0000535#ifndef DISABLE_SPELLER
Chris Allegretta6df90f52002-07-19 01:08:59 +0000536 || !strcasecmp(rcopts[i].name, "speller")
Chris Allegretta6fe61492001-05-21 12:56:25 +0000537#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000538 ) {
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000539 if (*ptr == '\n' || *ptr == '\0') {
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000540 rcfile_error(_
541 ("option %s requires an argument"),
542 rcopts[i].name);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000543 continue;
544 }
545 option = ptr;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000546 if (*option == '"')
547 option++;
548 ptr = parse_argument(ptr);
549#ifdef DEBUG
550 fprintf(stderr, "option = %s\n", option);
551#endif
552#ifndef DISABLE_OPERATINGDIR
553 if (!strcasecmp(rcopts[i].name, "operatingdir"))
554 operating_dir = mallocstrcpy(NULL, option);
555 else
556#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +0000557#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000558 if (!strcasecmp(rcopts[i].name, "fill")) {
559 char *first_error;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000560
Chris Allegretta7662c862003-01-13 01:35:15 +0000561 /* Using strtol() instead of atoi() lets
562 * us accept 0 while checking other
Chris Allegretta6df90f52002-07-19 01:08:59 +0000563 * errors. */
564 j = (int)strtol(option, &first_error, 10);
565 if (errno == ERANGE || *option == '\0' || *first_error != '\0')
566 rcfile_error(_("requested fill size %d invalid"),
Chris Allegretta1596d382002-03-07 00:46:17 +0000567 j);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000568 else
569 wrap_at = j;
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000570 } else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000571#endif
Chris Allegrettad76ca2b2002-03-03 22:52:52 +0000572#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000573 if (!strcasecmp(rcopts[i].name, "quotestr"))
574 quotestr = mallocstrcpy(NULL, option);
575 else
Chris Allegrettad76ca2b2002-03-03 22:52:52 +0000576#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +0000577#ifndef DISABLE_SPELLER
Chris Allegretta6df90f52002-07-19 01:08:59 +0000578 if (!strcasecmp(rcopts[i].name, "speller"))
579 alt_speller = mallocstrcpy(NULL, option);
580 else
Chris Allegretta6fe61492001-05-21 12:56:25 +0000581#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000582 {
583 char *first_error;
584
585 /* Using strtol instead of atoi lets us
586 * accept 0 while checking other
587 * errors. */
588 j = (int)strtol(option, &first_error, 10);
589 if (errno == ERANGE || *option == '\0' || *first_error != '\0')
590 rcfile_error(_("requested tab size %d invalid"),
591 j);
592 else
593 tabsize = j;
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000594 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000595 } else
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000596 SET(rcopts[i].flag);
597#ifdef DEBUG
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000598 fprintf(stderr, _("set flag %d!\n"),
599 rcopts[i].flag);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000600#endif
601 } else {
602 UNSET(rcopts[i].flag);
603#ifdef DEBUG
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000604 fprintf(stderr, _("unset flag %d!\n"),
605 rcopts[i].flag);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000606#endif
Chris Allegretta6c1e6612002-01-19 16:52:34 +0000607 }
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000608 }
609 }
610 }
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000611 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000612 free(buf);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000613 if (errors)
614 rcfile_error(_("Errors found in .nanorc file"));
615
616 return;
617}
618
619/* The main rc file function, tries to open the rc file */
620void do_rcfile(void)
621{
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000622 FILE *rcstream;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000623 const struct passwd *userage;
624 uid_t euid = geteuid();
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000625
Chris Allegretta6df90f52002-07-19 01:08:59 +0000626#ifdef SYSCONFDIR
627 assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
628 nanorc = charalloc(sizeof(SYSCONFDIR) + 7);
Chris Allegrettaff8a68c2002-02-16 20:34:57 +0000629 sprintf(nanorc, "%s/nanorc", SYSCONFDIR);
Chris Allegrettaff8a68c2002-02-16 20:34:57 +0000630 /* Try to open system nanorc */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000631 if ((rcstream = fopen(nanorc, "r")) != NULL) {
632 /* Parse it! */
633 parse_rcfile(rcstream);
634 fclose(rcstream);
635 }
636#endif
Chris Allegrettaff8a68c2002-02-16 20:34:57 +0000637
Chris Allegretta6df90f52002-07-19 01:08:59 +0000638 /* Determine home directory using getpwent(), don't rely on $HOME */
639 do {
640 userage = getpwent();
641 } while (userage != NULL && userage->pw_uid != euid);
642 endpwent();
Chris Allegrettaff8a68c2002-02-16 20:34:57 +0000643
Chris Allegretta78f0fc62002-03-29 19:41:57 +0000644 lineno = 0;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000645
Chris Allegretta5beed502003-01-05 20:41:21 +0000646 if (userage == NULL) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000647 rcfile_error(_("I can't find my home directory! Wah!"));
Chris Allegretta7662c862003-01-13 01:35:15 +0000648 SET(NO_RCFILE);
Chris Allegretta5beed502003-01-05 20:41:21 +0000649 } else {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000650 nanorc = nrealloc(nanorc, strlen(userage->pw_dir) + 9);
651 sprintf(nanorc, "%s/.nanorc", userage->pw_dir);
652
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000653#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
654 /* If we've already read $SYSCONFDIR/nanorc (if it's there), we're
655 root, and --disable-wrapping-as-root is used, turn wrapping off */
656 if (euid == 0)
657 SET(NO_WRAP);
658#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000659 if ((rcstream = fopen(nanorc, "r")) == NULL) {
660 /* Don't complain about the file not existing */
Chris Allegretta5beed502003-01-05 20:41:21 +0000661 if (errno != ENOENT) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000662 rcfile_error(_("Unable to open ~/.nanorc file, %s"),
663 strerror(errno));
Chris Allegretta5beed502003-01-05 20:41:21 +0000664 SET(NO_RCFILE);
665 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000666 } else {
667 parse_rcfile(rcstream);
668 fclose(rcstream);
669 }
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000670 }
671
Chris Allegretta6df90f52002-07-19 01:08:59 +0000672 free(nanorc);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +0000673#ifdef ENABLE_COLOR
674 set_colorpairs();
675#endif
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000676}
677
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000678#endif /* ENABLE_NANORC */