1 /*
2 * *rc file parser
3 * Copyright
4 * (C) 1992 Joseph H. Allen;
5 *
6 * This file is part of JOE (Joe's Own Editor)
7 */
8 #include "types.h"
9
10 /* Validate joerc file */
11
validate_rc()12 int validate_rc()
13 {
14 KMAP *k;
15 if (!(k = ngetcontext("main")) || kmap_empty(k)) {
16 logerror_0(joe_gettext(_("Missing or empty :main keymap\n")));
17 return -1;
18 }
19
20 if (!(k = ngetcontext("prompt")) || kmap_empty(k)) {
21 logerror_0(joe_gettext(_("Missing or empty :prompt keymap\n")));
22 return -1;
23 }
24
25 if (!(k = ngetcontext("query")) || kmap_empty(k)) {
26 logerror_0(joe_gettext(_("Missing or empty :query keymap\n")));
27 return -1;
28 }
29
30 if (!(k = ngetcontext("querya")) || kmap_empty(k)) {
31 logerror_0(joe_gettext(_("Missing or empty :querya keymap\n")));
32 return -1;
33 }
34
35 if (!(k = ngetcontext("querysr")) || kmap_empty(k)) {
36 logerror_0(joe_gettext(_("Missing or empty :querysr keymap\n")));
37 return -1;
38 }
39
40 if (!(k = ngetcontext("shell")) || kmap_empty(k)) {
41 logerror_0(joe_gettext(_("Missing or empty :shell keymap\n")));
42 }
43
44 if (!(k = ngetcontext("vtshell")) || kmap_empty(k)) {
45 logerror_0(joe_gettext(_("Missing or empty :vtshell keymap\n")));
46 }
47
48 return 0;
49 }
50
51 /* Parse a macro- allow it to cross lines */
52
multiparse(JFILE * fd,int * refline,char * buf,ptrdiff_t * ofst,int * referr,char * name)53 static MACRO *multiparse(JFILE *fd, int *refline, char *buf, ptrdiff_t *ofst, int *referr, char *name)
54 {
55 MACRO *m;
56 ptrdiff_t x = *ofst;
57 int err = *referr;
58 int line = *refline;
59 m = 0;
60 for (;;) {
61 m = mparse(m, buf + x, &x, 0);
62 if (x == -1) { /* Error */
63 err = -1;
64 logerror_2(joe_gettext(_("%s %d: Unknown command in macro\n")), name, line);
65 break;
66 } else if (x == -2) { /* Get more input */
67 jfgets(buf, 1024, fd);
68 ++line;
69 x = 0;
70 } else /* We're done */
71 break;
72 }
73 *referr = err;
74 *refline = line;
75 *ofst = x;
76 return m;
77 }
78
79 /* Process rc file
80 * Returns 0 if the rc file was successfully processed
81 * -1 if the rc file couldn't be opened
82 * 1 if there was a syntax error in the file
83 */
84
procrc(CAP * cap,char * name)85 int procrc(CAP *cap, char *name)
86 {
87 OPTIONS *o = &fdefault; /* Current options */
88 KMAP *context = NULL; /* Current context */
89 struct rc_menu *current_menu = NULL;
90 char buf[1024]; /* Input buffer */
91 char buf1[1024]; /* Input buffer */
92 JFILE *fd; /* rc file */
93 int line = 0; /* Line number */
94 int err = 0; /* Set to 1 if there was a syntax error */
95
96 zlcpy(buf, SIZEOF(buf), name);
97 #ifdef __MSDOS__
98 fd = jfopen(buf, "rt");
99 #else
100 fd = jfopen(buf, "r");
101 #endif
102
103 if (!fd)
104 return -1; /* Return if we couldn't open the rc file */
105
106 logmessage_1(joe_gettext(_("Processing '%s'...\n")), name);
107
108 while (jfgets(buf, SIZEOF(buf), fd)) {
109 line++;
110 switch (buf[0]) {
111 case ' ':
112 case '\t':
113 case '\n':
114 case '\f':
115 case 0:
116 break; /* Skip comment lines */
117
118 case '[': /* Select file types for file-type dependent options */
119 {
120 int x;
121
122 o = (OPTIONS *)joe_malloc(SIZEOF(OPTIONS));
123 *o = fdefault;
124 o->match = 0;
125 for (x = 0; buf[x] && buf[x] != ']' && buf[x] != '\r' && buf[x] != '\n' && buf[x] != ' ' && buf[x] != '\t'; ++x) ;
126 buf[x] = 0;
127 o->next = options_list;
128 options_list = o;
129 o->ftype = zdup(buf + 1);
130 }
131 break;
132 case '*': /* Select file types for file-type dependent options */
133 { /* Space and tab introduce comments- which means we can't have them in the regex */
134 if (o) {
135 struct options_match *m;
136 int x;
137 for (x = 0; buf[x] && buf[x] != '\n' && buf[x] != ' ' && buf[x] != '\t'; ++x) ;
138 buf[x] = 0;
139 m = (struct options_match *)joe_malloc(SIZEOF(struct options_match));
140 m->next = 0;
141 m->name_regex = zdup(buf);
142 m->contents_regex = 0;
143 m->r_contents_regex = 0;
144 m->next = o->match;
145 o->match = m;
146 }
147 }
148 break;
149 case '+': /* Set file contents match regex */
150 { /* No comments allowed- entire line used. */
151 int x;
152
153 for (x = 0; buf[x] && buf[x] != '\n' && buf[x] != '\r'; ++x) ;
154 buf[x] = 0;
155 if (o && o->match) {
156 if (o->match->contents_regex) {
157 struct options_match *m = (struct options_match *)joe_malloc(SIZEOF(struct options_match));
158 *m = *o->match;
159 m->next = o->match;
160 o->match = m;
161 }
162 o->match->contents_regex = zdup(buf+1);
163 }
164 }
165 break;
166 case '-': /* Set an option */
167 { /* parse option and arg. arg goes to end of line. This is bad. */
168 char *opt = buf + 1;
169 int x;
170 char *arg = NULL;
171
172 for (x = 0; buf[x] && buf[x] != '\n' && buf[x] != ' ' && buf[x] != '\t'; ++x) ;
173 if (buf[x] && buf[x] != '\n') {
174 buf[x] = 0;
175 for (arg = buf + ++x; buf[x] && buf[x] != '\n'; ++x) ;
176 }
177 buf[x] = 0;
178 if (!glopt(opt, arg, o, 2)) {
179 err = 1;
180 logerror_3(joe_gettext(_("%s %d: Unknown option %s\n")), name, line, opt);
181 }
182 }
183 break;
184 case '{': /* Process help text. No comment allowed after {name */
185 { /* everything after } is ignored. */
186 line = help_init(fd,buf,line);
187 }
188 break;
189 case ':': /* Select context */
190 {
191 ptrdiff_t x, c;
192 char ch;
193
194 for (x = 1; !joe_isspace_eos(locale_map,buf[x]); ++x) ;
195 ch = buf[x];
196 buf[x] = 0;
197 if (x != 1)
198 if (!zcmp(buf + 1, "def")) {
199 ptrdiff_t y;
200
201 for (buf[x] = ch; joe_isblank(locale_map,buf[x]); ++x) ;
202 for (y = x; !joe_isspace_eos(locale_map,buf[y]); ++y) ;
203 ch = buf[y];
204 buf[y] = 0;
205 zlcpy(buf1, SIZEOF(buf1), buf + x);
206 if (y != x) {
207 ptrdiff_t sta = y + 1;
208 MACRO *m;
209
210 if (joe_isblank(locale_map,ch)
211 && (m = multiparse(fd, &line, buf, &sta, &err, name)))
212 addcmd(buf1, m);
213 else {
214 err = 1;
215 logerror_2(joe_gettext(_("%s %d: macro missing from :def\n")), name, line);
216 }
217 } else {
218 err = 1;
219 logerror_2(joe_gettext(_("%s %d: command name missing from :def\n")), name, line);
220 }
221 } else if (!zcmp(buf + 1, "inherit")) {
222 if (context) {
223 for (buf[x] = ch; joe_isblank(locale_map,buf[x]); ++x) ;
224 for (c = x; !joe_isspace_eos(locale_map,buf[c]); ++c) ;
225 buf[c] = 0;
226 if (c != x)
227 kcpy(context, kmap_getcontext(buf + x));
228 else {
229 err = 1;
230 logerror_2(joe_gettext(_("%s %d: context name missing from :inherit\n")), name, line);
231 }
232 } else {
233 err = 1;
234 logerror_2(joe_gettext(_("%s %d: No context selected for :inherit\n")), name, line);
235 }
236 } else if (!zcmp(buf + 1, "include")) {
237 for (buf[x] = ch; joe_isblank(locale_map,buf[x]); ++x) ;
238 for (c = x; !joe_isspace_eos(locale_map,buf[c]); ++c) ;
239 buf[c] = 0;
240 if (c != x) {
241 char bf[1024];
242 char *p = getenv("HOME");
243 int rtn = -1;
244 bf[0] = 0;
245 if (p && buf[x] != '/') {
246 joe_snprintf_2(bf,SIZEOF(bf),"%s/.joe/%s",p,buf + x);
247 rtn = procrc(cap, bf);
248 }
249 if (rtn == -1 && buf[x] != '/') {
250 joe_snprintf_2(bf,SIZEOF(bf),"%s%s",JOERC,buf + x);
251 rtn = procrc(cap, bf);
252 }
253 if (rtn == -1 && buf[x] != '/') {
254 joe_snprintf_1(bf,SIZEOF(bf),"*%s",buf + x);
255 rtn = procrc(cap, bf);
256 }
257 if (rtn == -1 && buf[x] == '/') {
258 joe_snprintf_1(bf,SIZEOF(bf),"%s",buf + x);
259 rtn = procrc(cap, bf);
260 }
261 switch (rtn) {
262 case 1:
263 err = 1;
264 break;
265 case -1:
266 logerror_3(joe_gettext(_("%s %d: Couldn't open %s\n")), name, line, bf);
267 err = 1;
268 break;
269 }
270 context = 0;
271 o = &fdefault;
272 } else {
273 err = 1;
274 logerror_2(joe_gettext(_("%s %d: :include missing file name\n")), name, line);
275 }
276 } else if (!zcmp(buf + 1, "delete")) {
277 if (context) {
278 ptrdiff_t y;
279
280 for (buf[x] = ch; joe_isblank(locale_map,buf[x]); ++x) ;
281 for (y = x; buf[y] != 0 && buf[y] != '\t' && buf[y] != '\n' && (buf[y] != ' ' || buf[y + 1]
282 != ' '); ++y) ;
283 buf[y] = 0;
284 kdel(context, buf + x);
285 } else {
286 err = 1;
287 logerror_2(joe_gettext(_("%s %d: No context selected for :delete\n")), name, line);
288 }
289 } else if (!zcmp(buf + 1, "defmap")) {
290 for (buf[x] = ch; joe_isblank(locale_map,buf[x]); ++x) ;
291 for (c = x; !joe_isspace_eos(locale_map,buf[c]); ++c) ;
292 buf[c] = 0;
293 if (c != x) {
294 context = kmap_getcontext(buf + x);
295 current_menu = 0;
296 } else {
297 err = 1;
298 logerror_2(joe_gettext(_("%s %d: :defmap missing name\n")), name, line);
299 }
300 } else if (!zcmp(buf + 1, "defmenu")) {
301 MACRO *m = 0;
302 char d;
303 ptrdiff_t y;
304 for (buf[x] = ch; joe_isblank(locale_map,buf[x]); ++x) ;
305 for (c = x; !joe_isspace_eos(locale_map,buf[c]); ++c) ;
306 d = buf[c];
307 buf[c] = 0;
308 zlcpy(buf1, SIZEOF(buf1), buf + x);
309 buf[c] = d;
310 for (y = c; joe_isblank(locale_map, buf[y]); ++y);
311 if (!joe_isspace_eos(locale_map, buf[y]))
312 m = multiparse(fd, &line, buf, &y, &err, name);
313 current_menu = create_menu(buf1, m);
314 context = 0;
315 } else {
316 context = kmap_getcontext(buf + 1);
317 current_menu = 0;
318 /* err = 1;
319 logerror_2(joe_gettext(_("%s %d: unknown :command\n")), name, line);*/
320 }
321 else {
322 err = 1;
323 logerror_2(joe_gettext(_("%s %d: Invalid context name\n")), name, line);
324 }
325 }
326 break;
327 default: /* Get key-sequence to macro binding */
328 {
329 ptrdiff_t x, y;
330 MACRO *m;
331
332 if (!context && !current_menu) {
333 err = 1;
334 logerror_2(joe_gettext(_("%s %d: No context selected for macro to key-sequence binding\n")), name, line);
335 break;
336 }
337
338 x = 0;
339 m = multiparse(fd, &line, buf, &x, &err, name);
340 if (x == -1)
341 break;
342 if (!m)
343 break;
344
345 /* Skip to end of key sequence */
346 for (y = x; buf[y] != 0 && buf[y] != '\t' && buf[y] != '\n' && (buf[y] != ' ' || buf[y + 1] != ' '); ++y) ;
347 buf[y] = 0;
348
349 if (current_menu) {
350 /* Add menu entry */
351 add_menu_entry(current_menu, buf + x, m);
352 } else {
353 /* Add binding to context */
354 if (kadd(cap, context, buf + x, m) == -1) {
355 logerror_3(joe_gettext(_("%s %d: Bad key sequence '%s'\n")), name, line, buf + x);
356 err = 1;
357 }
358 }
359 }
360 break;
361 }
362 }
363 jfclose(fd); /* Close rc file */
364
365 /* Print proper ending string */
366 logmessage_1(joe_gettext(_("Finished processing %s\n")), name);
367
368 return err; /* 0 for success, 1 for syntax error */
369 }
370