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