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