Home | History | Annotate | Line # | Download | only in libedit
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