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