blob: b0b0c4e0e61be9632b271587147492d244b73a01 [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 *
8 * the Free Software Foundation; either version 1, or (at your option) *
9 * 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
42#define NUM_RCOPTS 14
43/* Static stuff for the nanorc file */
44rcoption rcopts[NUM_RCOPTS] =
45{
46{"regexp", USE_REGEXP},
47{"const", CONSTUPDATE},
48{"autoindent", AUTOINDENT},
49{"cut", CUT_TO_END},
50{"nofollow", FOLLOW_SYMLINKS},
51{"mouse", USE_MOUSE},
52{"pico", PICO_MODE},
Chris Allegretta6fe61492001-05-21 12:56:25 +000053
54#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta8d8e0122001-04-18 04:28:54 +000055{"fill", 0},
Chris Allegretta6fe61492001-05-21 12:56:25 +000056#endif
57
Chris Allegretta8d8e0122001-04-18 04:28:54 +000058{"speller", 0},
59{"tempfile", TEMP_OPT},
60{"view", VIEW_MODE},
61{"nowrap", NO_WRAP},
62{"nohelp", NO_HELP},
63{"suspend", SUSPEND}};
64
Chris Allegretta88520c92001-05-05 17:45:54 +000065/* We have an error in some part of the rcfile; put it on stderr and
66 make the user hit return to continue starting up nano */
Chris Allegretta8d8e0122001-04-18 04:28:54 +000067void rcfile_error(char *msg, ...)
68{
69 va_list ap;
70
71 fprintf(stderr, "\n");
72 va_start(ap, msg);
73 vfprintf(stderr, msg, ap);
74 va_end(ap);
75 fprintf(stderr, _("\nPress return to continue starting nano\n"));
76
77 while (getchar() != '\n')
78 ;
79
80}
81
Chris Allegretta88520c92001-05-05 17:45:54 +000082/* Just print the error (one of many, perhaps) but don't abort, yet */
Chris Allegretta8d8e0122001-04-18 04:28:54 +000083void rcfile_msg(int *errors, char *msg, ...)
84{
85 va_list ap;
86
87 if (!*errors) {
88 *errors = 1;
89 fprintf(stderr, "\n");
90 }
91 va_start(ap, msg);
92 vfprintf(stderr, msg, ap);
93 va_end(ap);
94 fprintf(stderr, "\n");
95
96}
97
Chris Allegretta88520c92001-05-05 17:45:54 +000098/* Parse the next word from the string. Returns NULL if we hit EOL */
Chris Allegretta8d8e0122001-04-18 04:28:54 +000099char *parse_next_word(char *ptr)
100{
101 while (*ptr != ' ' && *ptr != '\n' && ptr != '\0')
102 ptr++;
103
104 if (*ptr == '\0')
105 return NULL;
106
107 /* Null terminate and advance ptr */
108 *ptr++ = 0;
109
110 return ptr;
111}
112
113/* Parse the RC file, once it has been opened successfully */
114void parse_rcfile(FILE *rcstream, char *filename)
115{
116 char *buf, *ptr, *keyword, *option;
117 int set = 0, lineno = 0, i;
118 int errors = 0;
119
Chris Allegretta8d848af2001-05-18 04:44:16 +0000120 buf = charalloc(1024);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000121 while (fgets(buf, 1023, rcstream) > 0) {
122 lineno++;
123 ptr = buf;
124 while ((*ptr == ' ' || *ptr == '\t') &&
125 (*ptr != '\n' && *ptr != '\0'))
126 ptr++;
127
128 if (*ptr == '\n' || *ptr == '\0')
129 continue;
130
131 if (*ptr == '#') {
132#ifdef DEBUG
133 fprintf(stderr, _("parse_rcfile: Read a comment\n"));
134#endif
135 continue; /* Skip past commented lines */
136 }
137
138 /* Else skip to the next space */
139 keyword = ptr;
140 ptr = parse_next_word(ptr);
141 if (!ptr)
142 continue;
143
144 /* Else try to parse the keyword */
145 if (!strcasecmp(keyword, "set"))
146 set = 1;
147 else if (!strcasecmp(keyword, "unset"))
148 set = -1;
149 else {
150 rcfile_msg(&errors, _("Error in %s on line %d: command %s not understood"),
151 filename, lineno, keyword);
152 continue;
153 }
154
155 option = ptr;
156 ptr = parse_next_word(ptr);
157 /* We don't care if ptr == NULL, as it should if using proper syntax */
158
159 if (set != 0) {
160 for (i = 0; i <= NUM_RCOPTS - 1; i++) {
161 if (!strcasecmp(option, rcopts[i].name)) {
162#ifdef DEBUG
Jordi Mallachb4d6ad02001-05-24 13:10:06 +0000163 fprintf(stderr, _("parse_rcfile: Parsing option %s\n"),
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000164 rcopts[i].name);
165#endif
166 if (set == 1 || rcopts[i].flag == FOLLOW_SYMLINKS) {
Chris Allegretta6fe61492001-05-21 12:56:25 +0000167 if (
168#ifndef DISABLE_WRAPJUSTIFY
169 !strcasecmp(rcopts[i].name, "fill") ||
170#endif
171#ifndef DISABLE_SPELLER
172 !strcasecmp(rcopts[i].name, "speller")
173#else
174 0
175#endif
176 ) {
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000177
178 if (*ptr == '\n' || *ptr == '\0') {
179 rcfile_msg(&errors, _("Error in %s on line %d: option %s requires an argument"),
180 filename, lineno, rcopts[i].name);
181 continue;
182 }
183 option = ptr;
184 ptr = parse_next_word(ptr);
185 if (!strcasecmp(rcopts[i].name, "fill")) {
Chris Allegretta6fe61492001-05-21 12:56:25 +0000186#ifndef DISABLE_WRAPJUSTIFY
187
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000188 if ((i = atoi(option)) < MIN_FILL_LENGTH) {
189 rcfile_msg(&errors,
190 _("Error in %s on line %d: requested fill size %d too small"),
191 filename, lineno, option);
192 }
193 else
194 fill = i;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000195#endif
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000196 }
197 else {
Chris Allegretta6fe61492001-05-21 12:56:25 +0000198#ifndef DISABLE_SPELLER
Chris Allegretta8d848af2001-05-18 04:44:16 +0000199 alt_speller = charalloc(strlen(option) + 1);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000200 strcpy(alt_speller, option);
Chris Allegretta6fe61492001-05-21 12:56:25 +0000201#endif
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000202 }
203 } else
204 SET(rcopts[i].flag);
205#ifdef DEBUG
Jordi Mallachb4d6ad02001-05-24 13:10:06 +0000206 fprintf(stderr, _("set flag %d!\n"), rcopts[i].flag);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000207#endif
208 } else {
209 UNSET(rcopts[i].flag);
210#ifdef DEBUG
Jordi Mallachb4d6ad02001-05-24 13:10:06 +0000211 fprintf(stderr, _("unset flag %d!\n"), rcopts[i].flag);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000212#endif
213 }
214 }
215 }
216 }
217
218 }
219 if (errors)
220 rcfile_error(_("Errors found in .nanorc file"));
221
222 return;
223}
224
225/* The main rc file function, tries to open the rc file */
226void do_rcfile(void)
227{
228 char *nanorc;
229 char *unable = _("Unable to open ~/.nanorc file, %s");
230 struct stat fileinfo;
231 FILE *rcstream;
232
233 if (getenv("HOME") == NULL)
234 return;
235
Chris Allegretta88b09152001-05-17 11:35:43 +0000236 nanorc = charalloc(strlen(getenv("HOME")) + 10);
Chris Allegretta8d8e0122001-04-18 04:28:54 +0000237 sprintf(nanorc, "%s/.nanorc", getenv("HOME"));
238
239 if (stat(nanorc, &fileinfo) == -1) {
240
241 /* Abort if the file doesn't exist and there's some other kind
242 of error stat()ing it */
243 if (errno != ENOENT)
244 rcfile_error(unable, errno);
245 return;
246 }
247
248 if ((rcstream = fopen(nanorc, "r")) == NULL) {
249 rcfile_error(unable, strerror(errno));
250 return;
251 }
252
253 parse_rcfile(rcstream, nanorc);
254 fclose(rcstream);
255
256}
257
258
259#endif /* ENABLE_NANORC */
260