el.c revision 1.34 1 /* $NetBSD: el.c,v 1.34 2003/09/26 17:44:51 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94";
39 #else
40 __RCSID("$NetBSD: el.c,v 1.34 2003/09/26 17:44:51 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43
44 /*
45 * el.c: EditLine interface functions
46 */
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <stdarg.h>
52 #include "el.h"
53
54 /* el_init():
55 * Initialize editline and set default parameters.
56 */
57 public EditLine *
58 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
59 {
60
61 EditLine *el = (EditLine *) el_malloc(sizeof(EditLine));
62
63 if (el == NULL)
64 return (NULL);
65
66 memset(el, 0, sizeof(EditLine));
67
68 el->el_infd = fileno(fin);
69 el->el_outfile = fout;
70 el->el_errfile = ferr;
71 el->el_prog = strdup(prog);
72
73 /*
74 * Initialize all the modules. Order is important!!!
75 */
76 el->el_flags = 0;
77
78 if (term_init(el) == -1) {
79 free(el->el_prog);
80 el_free(el);
81 return NULL;
82 }
83 (void) key_init(el);
84 (void) map_init(el);
85 if (tty_init(el) == -1)
86 el->el_flags |= NO_TTY;
87 (void) ch_init(el);
88 (void) search_init(el);
89 (void) hist_init(el);
90 (void) prompt_init(el);
91 (void) sig_init(el);
92 (void) read_init(el);
93
94 return (el);
95 }
96
97
98 /* el_end():
99 * Clean up.
100 */
101 public void
102 el_end(EditLine *el)
103 {
104
105 if (el == NULL)
106 return;
107
108 el_reset(el);
109
110 term_end(el);
111 key_end(el);
112 map_end(el);
113 tty_end(el);
114 ch_end(el);
115 search_end(el);
116 hist_end(el);
117 prompt_end(el);
118 sig_end(el);
119
120 el_free((ptr_t) el->el_prog);
121 el_free((ptr_t) el);
122 }
123
124
125 /* el_reset():
126 * Reset the tty and the parser
127 */
128 public void
129 el_reset(EditLine *el)
130 {
131
132 tty_cookedmode(el);
133 ch_reset(el); /* XXX: Do we want that? */
134 }
135
136
137 /* el_set():
138 * set the editline parameters
139 */
140 public int
141 el_set(EditLine *el, int op, ...)
142 {
143 va_list va;
144 int rv = 0;
145
146 if (el == NULL)
147 return (-1);
148 va_start(va, op);
149
150 switch (op) {
151 case EL_PROMPT:
152 case EL_RPROMPT:
153 rv = prompt_set(el, va_arg(va, el_pfunc_t), op);
154 break;
155
156 case EL_TERMINAL:
157 rv = term_set(el, va_arg(va, char *));
158 break;
159
160 case EL_EDITOR:
161 rv = map_set_editor(el, va_arg(va, char *));
162 break;
163
164 case EL_SIGNAL:
165 if (va_arg(va, int))
166 el->el_flags |= HANDLE_SIGNALS;
167 else
168 el->el_flags &= ~HANDLE_SIGNALS;
169 break;
170
171 case EL_BIND:
172 case EL_TELLTC:
173 case EL_SETTC:
174 case EL_ECHOTC:
175 case EL_SETTY:
176 {
177 const char *argv[20];
178 int i;
179
180 for (i = 1; i < 20; i++)
181 if ((argv[i] = va_arg(va, char *)) == NULL)
182 break;
183
184 switch (op) {
185 case EL_BIND:
186 argv[0] = "bind";
187 rv = map_bind(el, i, argv);
188 break;
189
190 case EL_TELLTC:
191 argv[0] = "telltc";
192 rv = term_telltc(el, i, argv);
193 break;
194
195 case EL_SETTC:
196 argv[0] = "settc";
197 rv = term_settc(el, i, argv);
198 break;
199
200 case EL_ECHOTC:
201 argv[0] = "echotc";
202 rv = term_echotc(el, i, argv);
203 break;
204
205 case EL_SETTY:
206 argv[0] = "setty";
207 rv = tty_stty(el, i, argv);
208 break;
209
210 default:
211 rv = -1;
212 EL_ABORT((el->el_errfile, "Bad op %d\n", op));
213 break;
214 }
215 break;
216 }
217
218 case EL_ADDFN:
219 {
220 char *name = va_arg(va, char *);
221 char *help = va_arg(va, char *);
222 el_func_t func = va_arg(va, el_func_t);
223
224 rv = map_addfunc(el, name, help, func);
225 break;
226 }
227
228 case EL_HIST:
229 {
230 hist_fun_t func = va_arg(va, hist_fun_t);
231 ptr_t ptr = va_arg(va, char *);
232
233 rv = hist_set(el, func, ptr);
234 break;
235 }
236
237 case EL_EDITMODE:
238 if (va_arg(va, int))
239 el->el_flags &= ~EDIT_DISABLED;
240 else
241 el->el_flags |= EDIT_DISABLED;
242 rv = 0;
243 break;
244
245 case EL_GETCFN:
246 {
247 el_rfunc_t rc = va_arg(va, el_rfunc_t);
248 rv = el_read_setfn(el, rc);
249 break;
250 }
251
252 case EL_CLIENTDATA:
253 el->el_data = va_arg(va, void *);
254 break;
255
256 case EL_UNBUFFERED:
257 rv = va_arg(va, int);
258 if (rv && !(el->el_flags & UNBUFFERED)) {
259 el->el_flags |= UNBUFFERED;
260 read_prepare(el);
261 } else if (!rv && (el->el_flags & UNBUFFERED)) {
262 el->el_flags &= ~UNBUFFERED;
263 read_finish(el);
264 }
265 rv = 0;
266 break;
267
268 default:
269 rv = -1;
270 break;
271 }
272
273 va_end(va);
274 return (rv);
275 }
276
277
278 /* el_get():
279 * retrieve the editline parameters
280 */
281 public int
282 el_get(EditLine *el, int op, void *ret)
283 {
284 int rv;
285
286 if (el == NULL || ret == NULL)
287 return (-1);
288 switch (op) {
289 case EL_PROMPT:
290 case EL_RPROMPT:
291 rv = prompt_get(el, (void *) &ret, op);
292 break;
293
294 case EL_EDITOR:
295 rv = map_get_editor(el, (void *) &ret);
296 break;
297
298 case EL_SIGNAL:
299 *((int *) ret) = (el->el_flags & HANDLE_SIGNALS);
300 rv = 0;
301 break;
302
303 case EL_EDITMODE:
304 *((int *) ret) = (!(el->el_flags & EDIT_DISABLED));
305 rv = 0;
306 break;
307
308 case EL_TERMINAL:
309 term_get(el, (const char **)ret);
310 rv = 0;
311 break;
312
313 #if 0 /* XXX */
314 case EL_BIND:
315 case EL_TELLTC:
316 case EL_SETTC:
317 case EL_ECHOTC:
318 case EL_SETTY:
319 {
320 const char *argv[20];
321 int i;
322
323 for (i = 1; i < sizeof(argv) / sizeof(argv[0]); i++)
324 if ((argv[i] = va_arg(va, char *)) == NULL)
325 break;
326
327 switch (op) {
328 case EL_BIND:
329 argv[0] = "bind";
330 rv = map_bind(el, i, argv);
331 break;
332
333 case EL_TELLTC:
334 argv[0] = "telltc";
335 rv = term_telltc(el, i, argv);
336 break;
337
338 case EL_SETTC:
339 argv[0] = "settc";
340 rv = term_settc(el, i, argv);
341 break;
342
343 case EL_ECHOTC:
344 argv[0] = "echotc";
345 rv = term_echotc(el, i, argv);
346 break;
347
348 case EL_SETTY:
349 argv[0] = "setty";
350 rv = tty_stty(el, i, argv);
351 break;
352
353 default:
354 rv = -1;
355 EL_ABORT((el->errfile, "Bad op %d\n", op));
356 break;
357 }
358 break;
359 }
360
361 case EL_ADDFN:
362 {
363 char *name = va_arg(va, char *);
364 char *help = va_arg(va, char *);
365 el_func_t func = va_arg(va, el_func_t);
366
367 rv = map_addfunc(el, name, help, func);
368 break;
369 }
370
371 case EL_HIST:
372 {
373 hist_fun_t func = va_arg(va, hist_fun_t);
374 ptr_t ptr = va_arg(va, char *);
375 rv = hist_set(el, func, ptr);
376 }
377 break;
378 #endif /* XXX */
379
380 case EL_GETCFN:
381 *((el_rfunc_t *)ret) = el_read_getfn(el);
382 rv = 0;
383 break;
384
385 case EL_CLIENTDATA:
386 *((void **)ret) = el->el_data;
387 rv = 0;
388 break;
389
390 case EL_UNBUFFERED:
391 *((int *) ret) = (!(el->el_flags & UNBUFFERED));
392 rv = 0;
393 break;
394
395 default:
396 rv = -1;
397 }
398
399 return (rv);
400 }
401
402
403 /* el_line():
404 * Return editing info
405 */
406 public const LineInfo *
407 el_line(EditLine *el)
408 {
409
410 return (const LineInfo *) (void *) &el->el_line;
411 }
412
413
414 /* el_source():
415 * Source a file
416 */
417 public int
418 el_source(EditLine *el, const char *fname)
419 {
420 FILE *fp;
421 size_t len;
422 char *ptr;
423
424 fp = NULL;
425 if (fname == NULL) {
426 #ifdef HAVE_ISSETUGID
427 static const char elpath[] = "/.editrc";
428 char path[MAXPATHLEN];
429
430 if (issetugid())
431 return (-1);
432 if ((ptr = getenv("HOME")) == NULL)
433 return (-1);
434 if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
435 return (-1);
436 if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
437 return (-1);
438 fname = path;
439 #else
440 /*
441 * If issetugid() is missing, always return an error, in order
442 * to keep from inadvertently opening up the user to a security
443 * hole.
444 */
445 return (-1);
446 #endif
447 }
448 if (fp == NULL)
449 fp = fopen(fname, "r");
450 if (fp == NULL)
451 return (-1);
452
453 while ((ptr = fgetln(fp, &len)) != NULL) {
454 if (len > 0 && ptr[len - 1] == '\n')
455 --len;
456 ptr[len] = '\0';
457 if (parse_line(el, ptr) == -1) {
458 (void) fclose(fp);
459 return (-1);
460 }
461 }
462
463 (void) fclose(fp);
464 return (0);
465 }
466
467
468 /* el_resize():
469 * Called from program when terminal is resized
470 */
471 public void
472 el_resize(EditLine *el)
473 {
474 int lins, cols;
475 sigset_t oset, nset;
476
477 (void) sigemptyset(&nset);
478 (void) sigaddset(&nset, SIGWINCH);
479 (void) sigprocmask(SIG_BLOCK, &nset, &oset);
480
481 /* get the correct window size */
482 if (term_get_size(el, &lins, &cols))
483 term_change_size(el, lins, cols);
484
485 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
486 }
487
488
489 /* el_beep():
490 * Called from the program to beep
491 */
492 public void
493 el_beep(EditLine *el)
494 {
495
496 term_beep(el);
497 }
498
499
500 /* el_editmode()
501 * Set the state of EDIT_DISABLED from the `edit' command.
502 */
503 protected int
504 /*ARGSUSED*/
505 el_editmode(EditLine *el, int argc, const char **argv)
506 {
507 const char *how;
508
509 if (argv == NULL || argc != 2 || argv[1] == NULL)
510 return (-1);
511
512 how = argv[1];
513 if (strcmp(how, "on") == 0)
514 el->el_flags &= ~EDIT_DISABLED;
515 else if (strcmp(how, "off") == 0)
516 el->el_flags |= EDIT_DISABLED;
517 else {
518 (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how);
519 return (-1);
520 }
521 return (0);
522 }
523