blob: 29ed11539a9f59e5f059a890b5072d336b185720 [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 * *
5 * Copyright (C) 1999 Chris Allegretta *
6 * 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
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h>
25#include <errno.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include "config.h"
30#include "proto.h"
31#include "nano.h"
32
33#ifdef ENABLE_NANORC
34
35#ifndef NANO_SMALL
36#include <libintl.h>
37#define _(string) gettext(string)
38#else
39#define _(string) (string)
40#endif
41
Chris Allegrettab3655b42001-10-22 03:15:31 +000042#ifndef DISABLE_WRAPJUSTIFY
43 #define NUM_RCOPTS 18
44#else
45 #define NUM_RCOPTS 17
46#endif
47
Chris Allegretta8d8e0122001-04-18 04:28:54 +000048/* Static stuff for the nanorc file */
49rcoption rcopts[NUM_RCOPTS] =
50{
51{"regexp", USE_REGEXP},
52{"const", CONSTUPDATE},
53{"autoindent", AUTOINDENT},
54{"cut", CUT_TO_END},
55{"nofollow", FOLLOW_SYMLINKS},
56{"mouse", USE_MOUSE},
Chris Allegrettae1f14522001-09-19 03:19:43 +000057{"operatingdir", 0},
Chris Allegretta8d8e0122001-04-18 04:28:54 +000058{"pico", PICO_MODE},
Chris Allegretta66c33b82001-10-02 23:57:31 +000059{"tabsize", 0},
Chris Allegretta6fe61492001-05-21 12:56:25 +000060
61#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta8d8e0122001-04-18 04:28:54 +000062{"fill", 0},
Chris Allegretta6fe61492001-05-21 12:56:25 +000063#endif
64
Chris Allegretta8d8e0122001-04-18 04:28:54 +000065{"speller", 0},
66{"tempfile", TEMP_OPT},
67{"view", VIEW_MODE},
68{"nowrap", NO_WRAP},
69{"nohelp", NO_HELP},
Chris Allegretta2d7893d2001-07-11 02:08:33 +000070{"suspend", SUSPEND},
Chris Allegretta3e3ae942001-09-22 19:02:04 +000071{"multibuffer", MULTIBUFFER},
72{"smooth", SMOOTHSCROLL}};
Chris Allegretta8d8e0122001-04-18 04:28:54 +000073
Chris Allegretta88520c92001-05-05 17:45:54 +000074/* We have an error in some part of the rcfile; put it on stderr and
75 make the user hit return to continue starting up nano */
Chris Allegretta8d8e0122001-04-18 04:28:54 +000076void rcfile_error(char *msg, ...)
77{
78 va_list ap;
79
80 fprintf(stderr, "\n");
81 va_start(ap, msg);
82 vfprintf(stderr, msg, ap);
83 va_end(ap);
84 fprintf(stderr, _("\nPress return to continue starting nano\n"));
85
86 while (getchar() != '\n')
87 ;
88
89}
90
Chris Allegretta88520c92001-05-05 17:45:54 +000091/* Just print the error (one of many, perhaps) but don't abort, yet */
Chris Allegretta8d8e0122001-04-18 04:28:54 +000092void rcfile_msg(int *errors, char *msg, ...)
93{
94 va_list ap;
95
96 if (!*errors) {
97 *errors = 1;
98 fprintf(stderr, "\n");
99 }
100 va_start(ap, msg);
101 vfprintf(stderr, msg, ap);
102 va_end(ap);
103 fprintf(stderr, "\n");
104
105}
106
Chris Allegretta88520c92001-05-05 17:45:54 +0000107/* Parse the next word from the string. Returns NULL if we hit EOL */
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000108char *parse_next_word(char *ptr)
109{
Chris Allegretta13fd44b2002-01-02 13:59:11 +0000110 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n' && *ptr != '\0')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000111 ptr++;
112
Chris Allegretta13fd44b2002-01-02 13:59:11 +0000113 if (*ptr == '\0')
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000114 return NULL;
Chris Allegretta08893e02001-11-29 02:42:27 +0000115
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000116 /* Null terminate and advance ptr */
117 *ptr++ = 0;
118
Chris Allegretta08893e02001-11-29 02:42:27 +0000119 while ((*ptr == ' ' || *ptr == '\t') && *ptr != '\0')
120 ptr++;
121
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000122 return ptr;
123}
124
Chris Allegretta2fa11b82001-12-02 04:55:44 +0000125int colortoint(char *colorname, int *bright, char *filename, int *lineno)
Chris Allegretta08893e02001-11-29 02:42:27 +0000126{
127 int mcolor = 0;
128
129 if (colorname == NULL)
130 return -1;
131
132 if (strcasestr(colorname, "bright")) {
Chris Allegretta2fa11b82001-12-02 04:55:44 +0000133 *bright = 1;
Chris Allegretta08893e02001-11-29 02:42:27 +0000134 colorname += 6;
135 }
136
137 if (!strcasecmp(colorname, "green"))
138 mcolor += COLOR_GREEN;
139 else if (!strcasecmp(colorname, "red"))
140 mcolor += COLOR_RED;
141 else if (!strcasecmp(colorname, "blue"))
142 mcolor += COLOR_BLUE;
143 else if (!strcasecmp(colorname, "white"))
144 mcolor += COLOR_WHITE;
145 else if (!strcasecmp(colorname, "yellow"))
146 mcolor += COLOR_YELLOW;
147 else if (!strcasecmp(colorname, "cyan"))
148 mcolor += COLOR_CYAN;
149 else if (!strcasecmp(colorname, "magenta"))
150 mcolor += COLOR_MAGENTA;
151 else if (!strcasecmp(colorname, "black"))
152 mcolor += COLOR_BLACK;
153 else {
154 printf("Error in %s on line %d: color %s not understood.\n",
155 filename, *lineno, colorname);
156 printf("Valid colors are \"green\", \"red\", \"blue\", "
157 "\"white\", \"yellow\", \"cyan\", \"magenta\" and "
158 "\"black\", with the optional prefix \"bright\".\n");
159 exit(1);
160 }
161
162 return mcolor;
163}
164
165
166#ifdef ENABLE_COLOR
167/* Parse the color stuff into the colorstrings array */
168void parse_colors(FILE *rcstream, char *filename, int *lineno, char *buf, char *ptr)
169{
Chris Allegretta2fa11b82001-12-02 04:55:44 +0000170 int i = 0, fg, bg, bright = 0;
Chris Allegretta08893e02001-11-29 02:42:27 +0000171 char prev = '\\';
172 char *tmp = NULL, *beginning, *fgstr, *bgstr;
173 colortype *tmpcolor = NULL;
Chris Allegretta08893e02001-11-29 02:42:27 +0000174
175 fgstr = ptr;
176 ptr = parse_next_word(ptr);
177
178 if (ptr == NULL) {
179 printf("Error in %s on line %d: Missing color name.\n",
180 filename, *lineno);
181 exit(1);
182 }
183
184 if (strstr(fgstr, ",")) {
185 strtok(fgstr, ",");
186 bgstr = strtok(NULL, ",");
187 } else
188 bgstr = NULL;
189
Chris Allegretta2fa11b82001-12-02 04:55:44 +0000190 fg = colortoint(fgstr, &bright, filename, lineno);
191 bg = colortoint(bgstr, &bright, filename, lineno);
Chris Allegretta08893e02001-11-29 02:42:27 +0000192
193 /* Now the fun part, start adding regexps to individual strings
194 in the colorstrings array, woo! */
195
196 i = 0;
197 beginning = ptr;
198 while (*ptr != '\0') {
199 switch (*ptr) {
200 case '\n':
201 *ptr = ' ';
Chris Allegretta3795e5f2001-11-29 03:03:18 +0000202/* i++; */
Chris Allegretta08893e02001-11-29 02:42:27 +0000203 case ' ':
204 if (prev != '\\') {
205 /* This is the end of the regex, uh I guess.
206 Add it to the colorstrings array for this color */
207
208 tmp = NULL;
209 tmp = charalloc(i + 1);
210 strncpy(tmp, beginning, i);
211 tmp[i] = '\0';
212
213 ptr = parse_next_word(ptr);
214 if (ptr == NULL)
215 return;
216
217 if (colorstrings == NULL) {
218 colorstrings = nmalloc(sizeof(colortype));
219 colorstrings->fg = fg;
220 colorstrings->bg = bg;
Chris Allegretta2fa11b82001-12-02 04:55:44 +0000221 colorstrings->bright = bright;
Chris Allegretta08893e02001-11-29 02:42:27 +0000222 colorstrings->str = NULL;
223 colorstrings->str = nmalloc(sizeof(colorstr));
224 colorstrings->str->val = tmp;
225 colorstrings->str->next = NULL;
226 colorstrings->next = NULL;
227 } else {
Chris Allegretta2fa11b82001-12-02 04:55:44 +0000228 for (tmpcolor = colorstrings; tmpcolor->next != NULL;
229 tmpcolor = tmpcolor->next)
Chris Allegretta08893e02001-11-29 02:42:27 +0000230 ;
Chris Allegretta81cbfad2001-11-29 03:49:09 +0000231#ifdef DEBUG
Chris Allegretta08893e02001-11-29 02:42:27 +0000232 fprintf(stderr, "Adding new entry for fg %d bg %d\n", fg, bg);
Chris Allegretta81cbfad2001-11-29 03:49:09 +0000233#endif
Chris Allegretta08893e02001-11-29 02:42:27 +0000234
Chris Allegretta2fa11b82001-12-02 04:55:44 +0000235 tmpcolor->next = nmalloc(sizeof(colortype));
236 tmpcolor->next->fg = fg;
237 tmpcolor->next->bg = bg;
238 tmpcolor->next->bright = bright;
239 tmpcolor->next->str = nmalloc(sizeof(colorstr));
240 tmpcolor->next->str->val = tmp;
241 tmpcolor->next->str->next = NULL;
242 tmpcolor->next->next = NULL;
Chris Allegretta08893e02001-11-29 02:42:27 +0000243 }
244
245 i = 0;
246 beginning = ptr;
247 break;
248 }
249 /* Else drop through to the default case */
250 default:
251 i++;
252 prev = *ptr;
253 ptr++;
254 break;
255 }
256 }
257
258}
259#endif /* ENABLE_COLOR */
260
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000261/* Parse the RC file, once it has been opened successfully */
262void parse_rcfile(FILE *rcstream, char *filename)
263{
264 char *buf, *ptr, *keyword, *option;
265 int set = 0, lineno = 0, i;
266 int errors = 0;
267
Chris Allegretta8d848af2001-05-18 04:44:16 +0000268 buf = charalloc(1024);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000269 while (fgets(buf, 1023, rcstream) > 0) {
270 lineno++;
271 ptr = buf;
272 while ((*ptr == ' ' || *ptr == '\t') &&
273 (*ptr != '\n' && *ptr != '\0'))
274 ptr++;
275
276 if (*ptr == '\n' || *ptr == '\0')
277 continue;
278
279 if (*ptr == '#') {
280#ifdef DEBUG
281 fprintf(stderr, _("parse_rcfile: Read a comment\n"));
282#endif
283 continue; /* Skip past commented lines */
284 }
285
286 /* Else skip to the next space */
287 keyword = ptr;
288 ptr = parse_next_word(ptr);
289 if (!ptr)
290 continue;
291
292 /* Else try to parse the keyword */
293 if (!strcasecmp(keyword, "set"))
294 set = 1;
295 else if (!strcasecmp(keyword, "unset"))
296 set = -1;
Chris Allegretta08893e02001-11-29 02:42:27 +0000297#ifdef ENABLE_COLOR
298 else if (!strcasecmp(keyword, "color"))
299 parse_colors(rcstream, filename, &lineno, buf, ptr);
300#endif /* ENABLE_COLOR */
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000301 else {
302 rcfile_msg(&errors, _("Error in %s on line %d: command %s not understood"),
303 filename, lineno, keyword);
304 continue;
305 }
306
307 option = ptr;
308 ptr = parse_next_word(ptr);
309 /* We don't care if ptr == NULL, as it should if using proper syntax */
310
311 if (set != 0) {
312 for (i = 0; i <= NUM_RCOPTS - 1; i++) {
313 if (!strcasecmp(option, rcopts[i].name)) {
314#ifdef DEBUG
Jordi Mallachb4d6ad02001-05-24 13:10:06 +0000315 fprintf(stderr, _("parse_rcfile: Parsing option %s\n"),
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000316 rcopts[i].name);
317#endif
318 if (set == 1 || rcopts[i].flag == FOLLOW_SYMLINKS) {
Chris Allegretta6fe61492001-05-21 12:56:25 +0000319 if (
Chris Allegrettae1f14522001-09-19 03:19:43 +0000320 !strcasecmp(rcopts[i].name, "operatingdir") ||
Chris Allegretta66c33b82001-10-02 23:57:31 +0000321 !strcasecmp(rcopts[i].name, "tabsize") ||
Chris Allegretta6fe61492001-05-21 12:56:25 +0000322#ifndef DISABLE_WRAPJUSTIFY
323 !strcasecmp(rcopts[i].name, "fill") ||
324#endif
325#ifndef DISABLE_SPELLER
326 !strcasecmp(rcopts[i].name, "speller")
327#else
328 0
329#endif
330 ) {
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000331
332 if (*ptr == '\n' || *ptr == '\0') {
333 rcfile_msg(&errors, _("Error in %s on line %d: option %s requires an argument"),
334 filename, lineno, rcopts[i].name);
335 continue;
336 }
337 option = ptr;
338 ptr = parse_next_word(ptr);
339 if (!strcasecmp(rcopts[i].name, "fill")) {
Chris Allegretta6fe61492001-05-21 12:56:25 +0000340#ifndef DISABLE_WRAPJUSTIFY
341
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000342 if ((i = atoi(option)) < MIN_FILL_LENGTH) {
343 rcfile_msg(&errors,
344 _("Error in %s on line %d: requested fill size %d too small"),
Chris Allegrettaca1a82e2001-10-03 15:18:41 +0000345 filename, lineno, i);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000346 }
347 else
348 fill = i;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000349#endif
Chris Allegretta66c33b82001-10-02 23:57:31 +0000350 } else if (!strcasecmp(rcopts[i].name, "tabsize")) {
351 if ((i = atoi(option)) <= 0) {
352 rcfile_msg(&errors,
353 _("Error in %s on line %d: requested tab size %d too small"),
Chris Allegrettaca1a82e2001-10-03 15:18:41 +0000354 filename, lineno, i);
Chris Allegretta66c33b82001-10-02 23:57:31 +0000355 } else {
356 tabsize = i;
357 }
358 } else {
Chris Allegretta6fe61492001-05-21 12:56:25 +0000359#ifndef DISABLE_SPELLER
Chris Allegretta8d848af2001-05-18 04:44:16 +0000360 alt_speller = charalloc(strlen(option) + 1);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000361 strcpy(alt_speller, option);
Chris Allegretta6fe61492001-05-21 12:56:25 +0000362#endif
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000363 }
364 } else
365 SET(rcopts[i].flag);
366#ifdef DEBUG
Jordi Mallachb4d6ad02001-05-24 13:10:06 +0000367 fprintf(stderr, _("set flag %d!\n"), rcopts[i].flag);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000368#endif
369 } else {
370 UNSET(rcopts[i].flag);
371#ifdef DEBUG
Jordi Mallachb4d6ad02001-05-24 13:10:06 +0000372 fprintf(stderr, _("unset flag %d!\n"), rcopts[i].flag);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000373#endif
374 }
375 }
376 }
377 }
378
379 }
380 if (errors)
381 rcfile_error(_("Errors found in .nanorc file"));
382
383 return;
384}
385
386/* The main rc file function, tries to open the rc file */
387void do_rcfile(void)
388{
389 char *nanorc;
390 char *unable = _("Unable to open ~/.nanorc file, %s");
391 struct stat fileinfo;
392 FILE *rcstream;
393
Chris Allegretta08893e02001-11-29 02:42:27 +0000394
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000395 if (getenv("HOME") == NULL)
396 return;
397
Chris Allegretta88b09152001-05-17 11:35:43 +0000398 nanorc = charalloc(strlen(getenv("HOME")) + 10);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000399 sprintf(nanorc, "%s/.nanorc", getenv("HOME"));
400
401 if (stat(nanorc, &fileinfo) == -1) {
402
403 /* Abort if the file doesn't exist and there's some other kind
404 of error stat()ing it */
405 if (errno != ENOENT)
406 rcfile_error(unable, errno);
407 return;
408 }
409
410 if ((rcstream = fopen(nanorc, "r")) == NULL) {
411 rcfile_error(unable, strerror(errno));
412 return;
413 }
414
415 parse_rcfile(rcstream, nanorc);
416 fclose(rcstream);
417
418}
419
420
421#endif /* ENABLE_NANORC */
422