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