xref: /netbsd-src/lib/libedit/el.c (revision 8a8f936f250a330d54f8a24ed0e92aadf9743a7b)
1 /*	$NetBSD: el.c,v 1.24 2001/10/09 13:50:30 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. 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.24 2001/10/09 13:50:30 christos 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 #include <stdarg.h>
58 #include "el.h"
59 
60 /* el_init():
61  *	Initialize editline and set default parameters.
62  */
63 public EditLine *
64 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
65 {
66 
67 	EditLine *el = (EditLine *) el_malloc(sizeof(EditLine));
68 #ifdef DEBUG
69 	char *tty;
70 #endif
71 
72 	if (el == NULL)
73 		return (NULL);
74 
75 	memset(el, 0, sizeof(EditLine));
76 
77 	el->el_infd = fileno(fin);
78 	el->el_outfile = fout;
79 	el->el_errfile = ferr;
80 	el->el_prog = strdup(prog);
81 
82 	/*
83          * Initialize all the modules. Order is important!!!
84          */
85 	el->el_flags = 0;
86 
87 	(void) term_init(el);
88 	(void) key_init(el);
89 	(void) map_init(el);
90 	if (tty_init(el) == -1)
91 		el->el_flags |= NO_TTY;
92 	(void) ch_init(el);
93 	(void) search_init(el);
94 	(void) hist_init(el);
95 	(void) prompt_init(el);
96 	(void) sig_init(el);
97 	(void) read_init(el);
98 
99 	return (el);
100 }
101 
102 
103 /* el_end():
104  *	Clean up.
105  */
106 public void
107 el_end(EditLine *el)
108 {
109 
110 	if (el == NULL)
111 		return;
112 
113 	el_reset(el);
114 
115 	term_end(el);
116 	key_end(el);
117 	map_end(el);
118 	tty_end(el);
119 	ch_end(el);
120 	search_end(el);
121 	hist_end(el);
122 	prompt_end(el);
123 	sig_end(el);
124 
125 	el_free((ptr_t) el->el_prog);
126 	el_free((ptr_t) el);
127 }
128 
129 
130 /* el_reset():
131  *	Reset the tty and the parser
132  */
133 public void
134 el_reset(EditLine *el)
135 {
136 
137 	tty_cookedmode(el);
138 	ch_reset(el);		/* XXX: Do we want that? */
139 }
140 
141 
142 /* el_set():
143  *	set the editline parameters
144  */
145 public int
146 el_set(EditLine *el, int op, ...)
147 {
148 	va_list va;
149 	int rv;
150 
151 	if (el == NULL)
152 		return (-1);
153 	va_start(va, op);
154 
155 	switch (op) {
156 	case EL_PROMPT:
157 	case EL_RPROMPT:
158 		rv = prompt_set(el, va_arg(va, el_pfunc_t), op);
159 		break;
160 
161 	case EL_TERMINAL:
162 		rv = term_set(el, va_arg(va, char *));
163 		break;
164 
165 	case EL_EDITOR:
166 		rv = map_set_editor(el, va_arg(va, char *));
167 		break;
168 
169 	case EL_SIGNAL:
170 		if (va_arg(va, int))
171 			el->el_flags |= HANDLE_SIGNALS;
172 		else
173 			el->el_flags &= ~HANDLE_SIGNALS;
174 		rv = 0;
175 		break;
176 
177 	case EL_BIND:
178 	case EL_TELLTC:
179 	case EL_SETTC:
180 	case EL_ECHOTC:
181 	case EL_SETTY:
182 	{
183 		char *argv[20];
184 		int i;
185 
186 		for (i = 1; i < 20; i++)
187 			if ((argv[i] = va_arg(va, char *)) == NULL)
188 				break;
189 
190 		switch (op) {
191 		case EL_BIND:
192 			argv[0] = "bind";
193 			rv = map_bind(el, i, argv);
194 			break;
195 
196 		case EL_TELLTC:
197 			argv[0] = "telltc";
198 			rv = term_telltc(el, i, argv);
199 			break;
200 
201 		case EL_SETTC:
202 			argv[0] = "settc";
203 			rv = term_settc(el, i, argv);
204 			break;
205 
206 		case EL_ECHOTC:
207 			argv[0] = "echotc";
208 			rv = term_echotc(el, i, argv);
209 			break;
210 
211 		case EL_SETTY:
212 			argv[0] = "setty";
213 			rv = tty_stty(el, i, argv);
214 			break;
215 
216 		default:
217 			rv = -1;
218 			EL_ABORT((el->el_errfile, "Bad op %d\n", op));
219 			break;
220 		}
221 		break;
222 	}
223 
224 	case EL_ADDFN:
225 	{
226 		char *name = va_arg(va, char *);
227 		char *help = va_arg(va, char *);
228 		el_func_t func = va_arg(va, el_func_t);
229 
230 		rv = map_addfunc(el, name, help, func);
231 		break;
232 	}
233 
234 	case EL_HIST:
235 	{
236 		hist_fun_t func = va_arg(va, hist_fun_t);
237 		ptr_t ptr = va_arg(va, char *);
238 
239 		rv = hist_set(el, func, ptr);
240 		break;
241 	}
242 
243 	case EL_EDITMODE:
244 		if (va_arg(va, int))
245 			el->el_flags &= ~EDIT_DISABLED;
246 		else
247 			el->el_flags |= EDIT_DISABLED;
248 		rv = 0;
249 		break;
250 
251 	case EL_GETCFN:
252 	{
253 		el_rfunc_t rc = va_arg(va, el_rfunc_t);
254 		rv = el_read_setfn(el, rc);
255 		break;
256 	}
257 
258 	case EL_CLIENTDATA:
259 		el->el_data = va_arg(va, void *);
260 		break;
261 
262 	default:
263 		rv = -1;
264 	}
265 
266 	va_end(va);
267 	return (rv);
268 }
269 
270 
271 /* el_get():
272  *	retrieve the editline parameters
273  */
274 public int
275 el_get(EditLine *el, int op, void *ret)
276 {
277 	int rv;
278 
279 	if (el == NULL || ret == NULL)
280 		return (-1);
281 	switch (op) {
282 	case EL_PROMPT:
283 	case EL_RPROMPT:
284 		rv = prompt_get(el, (el_pfunc_t *) & ret, op);
285 		break;
286 
287 	case EL_EDITOR:
288 		rv = map_get_editor(el, (const char **) &ret);
289 		break;
290 
291 	case EL_SIGNAL:
292 		*((int *) ret) = (el->el_flags & HANDLE_SIGNALS);
293 		rv = 0;
294 		break;
295 
296 	case EL_EDITMODE:
297 		*((int *) ret) = (!(el->el_flags & EDIT_DISABLED));
298 		rv = 0;
299 		break;
300 
301 #if 0				/* XXX */
302 	case EL_TERMINAL:
303 		rv = term_get(el, (const char *) &ret);
304 		break;
305 
306 	case EL_BIND:
307 	case EL_TELLTC:
308 	case EL_SETTC:
309 	case EL_ECHOTC:
310 	case EL_SETTY:
311 	{
312 		char *argv[20];
313 		int i;
314 
315 		for (i = 1; i < 20; i++)
316 			if ((argv[i] = va_arg(va, char *)) == NULL)
317 				break;
318 
319 		switch (op) {
320 		case EL_BIND:
321 			argv[0] = "bind";
322 			rv = map_bind(el, i, argv);
323 			break;
324 
325 		case EL_TELLTC:
326 			argv[0] = "telltc";
327 			rv = term_telltc(el, i, argv);
328 			break;
329 
330 		case EL_SETTC:
331 			argv[0] = "settc";
332 			rv = term_settc(el, i, argv);
333 			break;
334 
335 		case EL_ECHOTC:
336 			argv[0] = "echotc";
337 			rv = term_echotc(el, i, argv);
338 			break;
339 
340 		case EL_SETTY:
341 			argv[0] = "setty";
342 			rv = tty_stty(el, i, argv);
343 			break;
344 
345 		default:
346 			rv = -1;
347 			EL_ABORT((el->errfile, "Bad op %d\n", op));
348 			break;
349 		}
350 		break;
351 	}
352 
353 	case EL_ADDFN:
354 	{
355 		char *name = va_arg(va, char *);
356 		char *help = va_arg(va, char *);
357 		el_func_t func = va_arg(va, el_func_t);
358 
359 		rv = map_addfunc(el, name, help, func);
360 		break;
361 	}
362 
363 	case EL_HIST:
364 		{
365 			hist_fun_t func = va_arg(va, hist_fun_t);
366 			ptr_t ptr = va_arg(va, char *);
367 			rv = hist_set(el, func, ptr);
368 		}
369 		break;
370 #endif /* XXX */
371 
372 	case EL_GETCFN:
373 		*((el_rfunc_t *)ret) = el_read_getfn(el);
374 		rv = 0;
375 		break;
376 
377 	case EL_CLIENTDATA:
378 		*((void **)ret) = el->el_data;
379 		rv = 0;
380 		break;
381 
382 	default:
383 		rv = -1;
384 	}
385 
386 	return (rv);
387 }
388 
389 
390 /* el_line():
391  *	Return editing info
392  */
393 public const LineInfo *
394 el_line(EditLine *el)
395 {
396 
397 	return (const LineInfo *) (void *) &el->el_line;
398 }
399 
400 static const char elpath[] = "/.editrc";
401 
402 /* el_source():
403  *	Source a file
404  */
405 public int
406 el_source(EditLine *el, const char *fname)
407 {
408 	FILE *fp;
409 	size_t len;
410 	char *ptr, path[MAXPATHLEN];
411 
412 	fp = NULL;
413 	if (fname == NULL) {
414 		if (issetugid())
415 			return (-1);
416 		if ((ptr = getenv("HOME")) == NULL)
417 			return (-1);
418 		if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
419 			return (-1);
420 		if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
421 			return (-1);
422 		fname = path;
423 	}
424 	if (fp == NULL)
425 		fp = fopen(fname, "r");
426 	if (fp == NULL)
427 		return (-1);
428 
429 	while ((ptr = fgetln(fp, &len)) != NULL) {
430 		if (len > 0 && ptr[len - 1] == '\n')
431 			--len;
432 		ptr[len] = '\0';
433 		if (parse_line(el, ptr) == -1) {
434 			(void) fclose(fp);
435 			return (-1);
436 		}
437 	}
438 
439 	(void) fclose(fp);
440 	return (0);
441 }
442 
443 
444 /* el_resize():
445  *	Called from program when terminal is resized
446  */
447 public void
448 el_resize(EditLine *el)
449 {
450 	int lins, cols;
451 	sigset_t oset, nset;
452 
453 	(void) sigemptyset(&nset);
454 	(void) sigaddset(&nset, SIGWINCH);
455 	(void) sigprocmask(SIG_BLOCK, &nset, &oset);
456 
457 	/* get the correct window size */
458 	if (term_get_size(el, &lins, &cols))
459 		term_change_size(el, lins, cols);
460 
461 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
462 }
463 
464 
465 /* el_beep():
466  *	Called from the program to beep
467  */
468 public void
469 el_beep(EditLine *el)
470 {
471 
472 	term_beep(el);
473 }
474 
475 
476 /* el_editmode()
477  *	Set the state of EDIT_DISABLED from the `edit' command.
478  */
479 protected int
480 /*ARGSUSED*/
481 el_editmode(EditLine *el, int argc, char **argv)
482 {
483 	const char *how;
484 
485 	if (argv == NULL || argc != 2 || argv[1] == NULL)
486 		return (-1);
487 
488 	how = argv[1];
489 	if (strcmp(how, "on") == 0)
490 		el->el_flags &= ~EDIT_DISABLED;
491 	else if (strcmp(how, "off") == 0)
492 		el->el_flags |= EDIT_DISABLED;
493 	else {
494 		(void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how);
495 		return (-1);
496 	}
497 	return (0);
498 }
499