el.c revision 1.55 1 /* $NetBSD: el.c,v 1.55 2009/07/25 21:19:23 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.55 2009/07/25 21:19:23 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 <ctype.h>
53 #include "el.h"
54
55 /* el_init():
56 * Initialize editline and set default parameters.
57 */
58 public EditLine *
59 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
60 {
61
62 EditLine *el = (EditLine *) el_malloc(sizeof(EditLine));
63
64 if (el == NULL)
65 return (NULL);
66
67 memset(el, 0, sizeof(EditLine));
68
69 el->el_infile = fin;
70 el->el_outfile = fout;
71 el->el_errfile = ferr;
72
73 el->el_infd = fileno(fin);
74
75 if ((el->el_prog = el_strdup(prog)) == NULL) {
76 el_free(el);
77 return NULL;
78 }
79
80 /*
81 * Initialize all the modules. Order is important!!!
82 */
83 el->el_flags = 0;
84
85 if (term_init(el) == -1) {
86 el_free(el->el_prog);
87 el_free(el);
88 return NULL;
89 }
90 (void) key_init(el);
91 (void) map_init(el);
92 if (tty_init(el) == -1)
93 el->el_flags |= NO_TTY;
94 (void) ch_init(el);
95 (void) search_init(el);
96 (void) hist_init(el);
97 (void) prompt_init(el);
98 (void) sig_init(el);
99 (void) read_init(el);
100
101 return (el);
102 }
103
104
105 /* el_end():
106 * Clean up.
107 */
108 public void
109 el_end(EditLine *el)
110 {
111
112 if (el == NULL)
113 return;
114
115 el_reset(el);
116
117 term_end(el);
118 key_end(el);
119 map_end(el);
120 tty_end(el);
121 ch_end(el);
122 search_end(el);
123 hist_end(el);
124 prompt_end(el);
125 sig_end(el);
126
127 el_free((ptr_t) el->el_prog);
128 el_free((ptr_t) el);
129 }
130
131
132 /* el_reset():
133 * Reset the tty and the parser
134 */
135 public void
136 el_reset(EditLine *el)
137 {
138
139 tty_cookedmode(el);
140 ch_reset(el, 0); /* XXX: Do we want that? */
141 }
142
143
144 /* el_set():
145 * set the editline parameters
146 */
147 public int
148 el_set(EditLine *el, int op, ...)
149 {
150 va_list ap;
151 int rv = 0;
152
153 if (el == NULL)
154 return (-1);
155 va_start(ap, op);
156
157 switch (op) {
158 case EL_PROMPT:
159 case EL_RPROMPT: {
160 el_pfunc_t p = va_arg(ap, el_pfunc_t);
161
162 rv = prompt_set(el, p, 0, op);
163 break;
164 }
165
166 case EL_PROMPT_ESC:
167 case EL_RPROMPT_ESC: {
168 el_pfunc_t p = va_arg(ap, el_pfunc_t);
169 char c = va_arg(ap, int);
170
171 rv = prompt_set(el, p, c, op);
172 break;
173 }
174
175 case EL_TERMINAL:
176 rv = term_set(el, va_arg(ap, char *));
177 break;
178
179 case EL_EDITOR:
180 rv = map_set_editor(el, va_arg(ap, char *));
181 break;
182
183 case EL_SIGNAL:
184 if (va_arg(ap, int))
185 el->el_flags |= HANDLE_SIGNALS;
186 else
187 el->el_flags &= ~HANDLE_SIGNALS;
188 break;
189
190 case EL_BIND:
191 case EL_TELLTC:
192 case EL_SETTC:
193 case EL_GETTC:
194 case EL_ECHOTC:
195 case EL_SETTY:
196 {
197 const char *argv[20];
198 int i;
199
200 for (i = 1; i < 20; i++)
201 if ((argv[i] = va_arg(ap, char *)) == NULL)
202 break;
203
204 switch (op) {
205 case EL_BIND:
206 argv[0] = "bind";
207 rv = map_bind(el, i, argv);
208 break;
209
210 case EL_TELLTC:
211 argv[0] = "telltc";
212 rv = term_telltc(el, i, argv);
213 break;
214
215 case EL_SETTC:
216 argv[0] = "settc";
217 rv = term_settc(el, i, argv);
218 break;
219
220 case EL_ECHOTC:
221 argv[0] = "echotc";
222 rv = term_echotc(el, i, argv);
223 break;
224
225 case EL_SETTY:
226 argv[0] = "setty";
227 rv = tty_stty(el, i, argv);
228 break;
229
230 default:
231 rv = -1;
232 EL_ABORT((el->el_errfile, "Bad op %d\n", op));
233 break;
234 }
235 break;
236 }
237
238 case EL_ADDFN:
239 {
240 char *name = va_arg(ap, char *);
241 char *help = va_arg(ap, char *);
242 el_func_t func = va_arg(ap, el_func_t);
243
244 rv = map_addfunc(el, name, help, func);
245 break;
246 }
247
248 case EL_HIST:
249 {
250 hist_fun_t func = va_arg(ap, hist_fun_t);
251 ptr_t ptr = va_arg(ap, char *);
252
253 rv = hist_set(el, func, ptr);
254 break;
255 }
256
257 case EL_EDITMODE:
258 if (va_arg(ap, int))
259 el->el_flags &= ~EDIT_DISABLED;
260 else
261 el->el_flags |= EDIT_DISABLED;
262 rv = 0;
263 break;
264
265 case EL_GETCFN:
266 {
267 el_rfunc_t rc = va_arg(ap, el_rfunc_t);
268 rv = el_read_setfn(el, rc);
269 break;
270 }
271
272 case EL_CLIENTDATA:
273 el->el_data = va_arg(ap, void *);
274 break;
275
276 case EL_UNBUFFERED:
277 rv = va_arg(ap, int);
278 if (rv && !(el->el_flags & UNBUFFERED)) {
279 el->el_flags |= UNBUFFERED;
280 read_prepare(el);
281 } else if (!rv && (el->el_flags & UNBUFFERED)) {
282 el->el_flags &= ~UNBUFFERED;
283 read_finish(el);
284 }
285 rv = 0;
286 break;
287
288 case EL_PREP_TERM:
289 rv = va_arg(ap, int);
290 if (rv)
291 (void) tty_rawmode(el);
292 else
293 (void) tty_cookedmode(el);
294 rv = 0;
295 break;
296
297 case EL_SETFP:
298 {
299 FILE *fp;
300 int what;
301
302 what = va_arg(ap, int);
303 fp = va_arg(ap, FILE *);
304
305 rv = 0;
306 switch (what) {
307 case 0:
308 el->el_infile = fp;
309 el->el_infd = fileno(fp);
310 break;
311 case 1:
312 el->el_outfile = fp;
313 break;
314 case 2:
315 el->el_errfile = fp;
316 break;
317 default:
318 rv = -1;
319 break;
320 }
321 break;
322 }
323
324 case EL_REFRESH:
325 re_clear_display(el);
326 re_refresh(el);
327 term__flush(el);
328 break;
329
330 default:
331 rv = -1;
332 break;
333 }
334
335 va_end(ap);
336 return (rv);
337 }
338
339
340 /* el_get():
341 * retrieve the editline parameters
342 */
343 public int
344 el_get(EditLine *el, int op, ...)
345 {
346 va_list ap;
347 int rv;
348
349 if (el == NULL)
350 return -1;
351
352 va_start(ap, op);
353
354 switch (op) {
355 case EL_PROMPT:
356 case EL_RPROMPT: {
357 el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
358 char *c = va_arg(ap, char *);
359
360 rv = prompt_get(el, p, c, op);
361 break;
362 }
363
364 case EL_EDITOR:
365 rv = map_get_editor(el, va_arg(ap, const char **));
366 break;
367
368 case EL_SIGNAL:
369 *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
370 rv = 0;
371 break;
372
373 case EL_EDITMODE:
374 *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
375 rv = 0;
376 break;
377
378 case EL_TERMINAL:
379 term_get(el, va_arg(ap, const char **));
380 rv = 0;
381 break;
382
383 case EL_GETTC:
384 {
385 static char name[] = "gettc";
386 char *argv[20];
387 int i;
388
389 for (i = 1; i < (int)(sizeof(argv) / sizeof(argv[0])); i++)
390 if ((argv[i] = va_arg(ap, char *)) == NULL)
391 break;
392
393 switch (op) {
394 case EL_GETTC:
395 argv[0] = name;
396 rv = term_gettc(el, i, argv);
397 break;
398
399 default:
400 rv = -1;
401 EL_ABORT((el->el_errfile, "Bad op %d\n", op));
402 break;
403 }
404 break;
405 }
406
407 #if 0 /* XXX */
408 case EL_ADDFN:
409 {
410 char *name = va_arg(ap, char *);
411 char *help = va_arg(ap, char *);
412 el_func_t func = va_arg(ap, el_func_t);
413
414 rv = map_addfunc(el, name, help, func);
415 break;
416 }
417
418 case EL_HIST:
419 {
420 hist_fun_t func = va_arg(ap, hist_fun_t);
421 ptr_t ptr = va_arg(ap, char *);
422 rv = hist_set(el, func, ptr);
423 }
424 break;
425 #endif /* XXX */
426
427 case EL_GETCFN:
428 *va_arg(ap, el_rfunc_t *) = el_read_getfn(el);
429 rv = 0;
430 break;
431
432 case EL_CLIENTDATA:
433 *va_arg(ap, void **) = el->el_data;
434 rv = 0;
435 break;
436
437 case EL_UNBUFFERED:
438 *va_arg(ap, int *) = (!(el->el_flags & UNBUFFERED));
439 rv = 0;
440 break;
441
442 case EL_GETFP:
443 {
444 int what;
445 FILE **fpp;
446
447 what = va_arg(ap, int);
448 fpp = va_arg(ap, FILE **);
449 rv = 0;
450 switch (what) {
451 case 0:
452 *fpp = el->el_infile;
453 break;
454 case 1:
455 *fpp = el->el_outfile;
456 break;
457 case 2:
458 *fpp = el->el_errfile;
459 break;
460 default:
461 rv = -1;
462 break;
463 }
464 break;
465 }
466 default:
467 rv = -1;
468 break;
469 }
470 va_end(ap);
471
472 return (rv);
473 }
474
475
476 /* el_line():
477 * Return editing info
478 */
479 public const LineInfo *
480 el_line(EditLine *el)
481 {
482
483 return (const LineInfo *) (void *) &el->el_line;
484 }
485
486
487 /* el_source():
488 * Source a file
489 */
490 public int
491 el_source(EditLine *el, const char *fname)
492 {
493 FILE *fp;
494 size_t len;
495 char *ptr;
496 #ifdef HAVE_ISSETUGID
497 char path[MAXPATHLEN];
498 #endif
499
500 fp = NULL;
501 if (fname == NULL) {
502 #ifdef HAVE_ISSETUGID
503 static const char elpath[] = "/.editrc";
504
505 if (issetugid())
506 return (-1);
507 if ((ptr = getenv("HOME")) == NULL)
508 return (-1);
509 if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
510 return (-1);
511 if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
512 return (-1);
513 fname = path;
514 #else
515 /*
516 * If issetugid() is missing, always return an error, in order
517 * to keep from inadvertently opening up the user to a security
518 * hole.
519 */
520 return (-1);
521 #endif
522 }
523 if (fp == NULL)
524 fp = fopen(fname, "r");
525 if (fp == NULL)
526 return (-1);
527
528 while ((ptr = fgetln(fp, &len)) != NULL) {
529 if (len > 0 && ptr[len - 1] == '\n')
530 --len;
531 ptr[len] = '\0';
532
533 /* loop until first non-space char or EOL */
534 while (*ptr != '\0' && isspace((unsigned char)*ptr))
535 ptr++;
536 if (*ptr == '#')
537 continue; /* ignore, this is a comment line */
538
539 if (parse_line(el, ptr) == -1) {
540 (void) fclose(fp);
541 return (-1);
542 }
543 }
544
545 (void) fclose(fp);
546 return (0);
547 }
548
549
550 /* el_resize():
551 * Called from program when terminal is resized
552 */
553 public void
554 el_resize(EditLine *el)
555 {
556 int lins, cols;
557 sigset_t oset, nset;
558
559 (void) sigemptyset(&nset);
560 (void) sigaddset(&nset, SIGWINCH);
561 (void) sigprocmask(SIG_BLOCK, &nset, &oset);
562
563 /* get the correct window size */
564 if (term_get_size(el, &lins, &cols))
565 term_change_size(el, lins, cols);
566
567 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
568 }
569
570
571 /* el_beep():
572 * Called from the program to beep
573 */
574 public void
575 el_beep(EditLine *el)
576 {
577
578 term_beep(el);
579 }
580
581
582 /* el_editmode()
583 * Set the state of EDIT_DISABLED from the `edit' command.
584 */
585 protected int
586 /*ARGSUSED*/
587 el_editmode(EditLine *el, int argc, const char **argv)
588 {
589 const char *how;
590
591 if (argv == NULL || argc != 2 || argv[1] == NULL)
592 return (-1);
593
594 how = argv[1];
595 if (strcmp(how, "on") == 0) {
596 el->el_flags &= ~EDIT_DISABLED;
597 tty_rawmode(el);
598 } else if (strcmp(how, "off") == 0) {
599 tty_cookedmode(el);
600 el->el_flags |= EDIT_DISABLED;
601 }
602 else {
603 (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how);
604 return (-1);
605 }
606 return (0);
607 }
608