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