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