Home | History | Annotate | Line # | Download | only in libedit
readline.c revision 1.7
      1 /*	$NetBSD: readline.c,v 1.7 1999/07/02 15:21:26 simonb Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jaromir Dolecek.
      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 NetBSD
     21  *	Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 #if !defined(lint) && !defined(SCCSID)
     41 __RCSID("$NetBSD: readline.c,v 1.7 1999/07/02 15:21:26 simonb Exp $");
     42 #endif /* not lint && not SCCSID */
     43 
     44 #include <sys/types.h>
     45 #include <sys/stat.h>
     46 #include <stdio.h>
     47 #include <dirent.h>
     48 #include <string.h>
     49 #include <pwd.h>
     50 #include <ctype.h>
     51 #include <stdlib.h>
     52 #include <unistd.h>
     53 #include <limits.h>
     54 #include "histedit.h"
     55 #include "readline.h"
     56 #include "sys.h"
     57 #include "el.h"
     58 
     59 /* for rl_complete() */
     60 #define TAB		'\r'
     61 
     62 /* see comment at the #ifdef for sense of this */
     63 #define GDB_411_HACK
     64 
     65 /* readline compatibility stuff - look at readline sources/documentation */
     66 /* to see what these variables mean */
     67 const char     *rl_library_version = "EditLine wrapper";
     68 char           *rl_readline_name = "";
     69 FILE           *rl_instream = NULL;
     70 FILE           *rl_outstream = NULL;
     71 int             rl_point = 0;
     72 int             rl_end = 0;
     73 char           *rl_line_buffer = NULL;
     74 
     75 int             history_base = 1;	/* probably never subject to change */
     76 int             history_length = 0;
     77 int             max_input_history = 0;
     78 char            history_expansion_char = '!';
     79 char            history_subst_char = '^';
     80 char           *history_no_expand_chars = " \t\n=(";
     81 Function       *history_inhibit_expansion_function = NULL;
     82 
     83 int             rl_inhibit_completion = 0;
     84 int             rl_attempted_completion_over = 0;
     85 char           *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
     86 char           *rl_completer_word_break_characters = NULL;
     87 char           *rl_completer_quote_characters = NULL;
     88 CPFunction     *rl_completion_entry_function = NULL;
     89 CPPFunction    *rl_attempted_completion_function = NULL;
     90 
     91 /* used for readline emulation */
     92 static History *h = NULL;
     93 static EditLine *e = NULL;
     94 
     95 /* internal functions */
     96 static unsigned char _el_rl_complete __P((EditLine *, int));
     97 static char *_get_prompt __P((EditLine *));
     98 static HIST_ENTRY *_move_history __P((int));
     99 static int _history_search_gen __P((const char *, int, int));
    100 static int _history_expand_command __P((const char *, size_t, char **));
    101 static char *_rl_compat_sub __P((const char *, const char *,
    102      const char *, int));
    103 static int rl_complete_internal __P((int));
    104 
    105 /*
    106  * needed for easy prompt switching
    107  */
    108 static char    *el_rl_prompt = NULL;
    109 
    110 /* ARGSUSED */
    111 static char *
    112 _get_prompt(el)
    113 	EditLine *el;
    114 {
    115 	return el_rl_prompt;
    116 }
    117 
    118 /*
    119  * generic function for moving around history
    120  */
    121 static HIST_ENTRY *
    122 _move_history(op)
    123 	int op;
    124 {
    125 	HistEvent ev;
    126 	static HIST_ENTRY rl_he;
    127 
    128 	if (history(h, &ev, op) != 0)
    129 		return (HIST_ENTRY *) NULL;
    130 
    131 	rl_he.line = ev.str;
    132 	rl_he.data = "";
    133 
    134 	return &rl_he;
    135 }
    136 
    137 
    138 /*
    139  * READLINE compatibility stuff
    140  */
    141 
    142 /*
    143  * initialize rl compat stuff
    144  */
    145 int
    146 rl_initialize()
    147 {
    148 	HistEvent ev;
    149 	const LineInfo *li;
    150 
    151 	if (e != NULL)
    152 		el_end(e);
    153 	if (h != NULL)
    154 		history_end(h);
    155 
    156 	if (!rl_instream)
    157 		rl_instream = stdin;
    158 	if (!rl_outstream)
    159 		rl_outstream = stdout;
    160 	e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr);
    161 
    162 	h = history_init();
    163 	if (!e || !h)
    164 		return -1;
    165 
    166 	history(h, &ev, H_SETSIZE, INT_MAX);	/* unlimited */
    167 	history_length = 0;
    168 	max_input_history = INT_MAX;
    169 	el_set(e, EL_HIST, history, h);
    170 
    171 	/* for proper prompt printing in readline() */
    172 	el_rl_prompt = strdup("");
    173 	el_set(e, EL_PROMPT, _get_prompt);
    174 	el_set(e, EL_SIGNAL, 1);
    175 
    176 	/* set default mode to "emacs"-style and read setting afterwards */
    177 	/* so this can be overriden */
    178 	el_set(e, EL_EDITOR, "emacs");
    179 
    180 	/* for word completition - this has to go AFTER rebinding keys */
    181 	/* to emacs-style */
    182 	el_set(e, EL_ADDFN, "rl_complete",
    183 	       "ReadLine compatible completition function",
    184 	       _el_rl_complete);
    185 	el_set(e, EL_BIND, "^I", "rl_complete", NULL);
    186 
    187 	/* read settings from configuration file */
    188 	el_source(e, NULL);
    189 
    190 	/* some readline apps do use this */
    191 	li = el_line(e);
    192 	/* LINTED const cast */
    193 	rl_line_buffer = (char *) li->buffer;
    194 	rl_point = rl_end = 0;
    195 
    196 	return 0;
    197 }
    198 
    199 /*
    200  * read one line from input stream and return it, chomping
    201  * trailing newline (if there is any)
    202  */
    203 char *
    204 readline(const char *prompt)
    205 {
    206 	HistEvent ev;
    207 	int count;
    208 	const char *ret;
    209 
    210 	if (e == NULL || h == NULL)
    211 		rl_initialize();
    212 
    213 	/* set the prompt */
    214 	if (strcmp(el_rl_prompt, prompt) != 0) {
    215 		free(el_rl_prompt);
    216 		el_rl_prompt = strdup(prompt);
    217 	}
    218 	/* get one line from input stream */
    219 	ret = el_gets(e, &count);
    220 
    221 	if (ret && count > 0) {
    222 		char *foo;
    223 		int lastidx;
    224 
    225 		foo = strdup(ret);
    226 		lastidx = count - 1;
    227 		if (foo[lastidx] == '\n')
    228 			foo[lastidx] = '\0';
    229 
    230 		ret = foo;
    231 	} else
    232 		ret = NULL;
    233 
    234 	history(h, &ev, H_GETSIZE);
    235 	history_length = ev.num;
    236 
    237 	/* LINTED const cast */
    238 	return (char *) ret;
    239 }
    240 
    241 /*
    242  * history functions
    243  */
    244 
    245 /*
    246  * is normally called before application starts to use
    247  * history expansion functions
    248  */
    249 void
    250 using_history()
    251 {
    252 	if (h == NULL || e == NULL)
    253 		rl_initialize();
    254 }
    255 
    256 /*
    257  * substitute ``what'' with ``with'', returning resulting string; if
    258  * globally == 1, substitutes all occurences of what, otherwise only the
    259  * first one
    260  */
    261 /* ARGSUSED */
    262 static char    *
    263 _rl_compat_sub(str, what, with, globally)
    264 	const char     *str, *what, *with;
    265 	int             globally;
    266 {
    267 	char           *result;
    268 	const char     *temp, *new;
    269 	int             len, with_len, what_len, add;
    270 	size_t		size, i;
    271 
    272 	result = malloc((size = 16));
    273 	temp = str;
    274 	with_len = strlen(with);
    275 	what_len = strlen(what);
    276 	len = 0;
    277 	do {
    278 		new = strstr(temp, what);
    279 		if (new) {
    280 			i = new - temp;
    281 			add = i + with_len;
    282 			if (i + add + 1 >= size) {
    283 				size += add + 1;
    284 				result = realloc(result, size);
    285 			}
    286 			(void)strncpy(&result[len], temp, i);
    287 			len += i;
    288 			(void)strcpy(&result[len], with);	/* safe */
    289 			len += with_len;
    290 			temp = new + what_len;
    291 		} else {
    292 			add = strlen(temp);
    293 			if (len + add + 1 >= size) {
    294 				size += add + 1;
    295 				result = realloc(result, size);
    296 			}
    297 			(void)strcpy(&result[len], temp);	/* safe */
    298 			len += add;
    299 			temp = NULL;
    300 		}
    301 	} while (temp);
    302 	result[len] = '\0';
    303 
    304 	return result;
    305 }
    306 
    307 /*
    308  * the real function doing history expansion - takes as argument command
    309  * to do and data upon which the command should be executed
    310  * does expansion the way I've understood readline documentation
    311  * word designator ``%'' isn't supported (yet ?)
    312  *
    313  * returns 0 if data was not modified, 1 if it was and 2 if the string
    314  * should be only printed and not executed; in case of error,
    315  * returns -1 and *result points to NULL
    316  * it's callers responsibility to free() string returned in *result
    317  */
    318 static int
    319 _history_expand_command(command, cmdlen, result)
    320 	const char     *command;
    321 	size_t          cmdlen;
    322 	char          **result;
    323 {
    324 	char          **arr, *tempcmd, *line, *search = NULL, *cmd;
    325 	const char     *event_data = NULL;
    326 	static char    *from = NULL, *to = NULL;
    327 	int             start = -1, end = -1, max, i, idx;
    328 	int             h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0,
    329 	                g_on = 0;
    330 	int             event_num = 0, retval;
    331 	size_t		cmdsize;
    332 
    333 	*result = NULL;
    334 
    335 	cmd = alloca(cmdlen + 1);
    336 	(void)strncpy(cmd, command, cmdlen);
    337 	cmd[cmdlen] = 0;
    338 
    339 	idx = 1;
    340 	/* find out which event to take */
    341 	if (cmd[idx] == history_expansion_char) {
    342 		event_num = history_length;
    343 		idx++;
    344 	} else {
    345 		int    off, num;
    346 		size_t len;
    347 		off = idx;
    348 		while (cmd[off] && !strchr(":^$*-%", cmd[off]))
    349 			off++;
    350 		num = atoi(&cmd[idx]);
    351 		if (num != 0) {
    352 			event_num = num;
    353 			if (num < 0)
    354 				event_num += history_length + 1;
    355 		} else {
    356 			int prefix = 1, curr_num;
    357 			HistEvent ev;
    358 
    359 			len = off - idx;
    360 			if (cmd[idx] == '?') {
    361 				idx++, len--;
    362 				if (cmd[off - 1] == '?')
    363 					len--;
    364 				else if (cmd[off] != '\n' && cmd[off] != '\0')
    365 					return -1;
    366 				prefix = 0;
    367 			}
    368 			search = alloca(len + 1);
    369 			(void)strncpy(search, &cmd[idx], len);
    370 			search[len] = '\0';
    371 
    372 			if (history(h, &ev, H_CURR) != 0)
    373 				return -1;
    374 			curr_num = ev.num;
    375 
    376 			if (prefix)
    377 				retval = history_search_prefix(search, -1);
    378 			else
    379 				retval = history_search(search, -1);
    380 
    381 			if (retval == -1) {
    382 				fprintf(rl_outstream, "%s: Event not found\n",
    383 					search);
    384 				return -1;
    385 			}
    386 			if (history(h, &ev, H_CURR) != 0)
    387 				return -1;
    388 			event_data = ev.str;
    389 
    390 			/* roll back to original position */
    391 			history(h, &ev, H_NEXT_EVENT, curr_num);
    392 		}
    393 		idx = off;
    394 	}
    395 
    396 	if (!event_data && event_num >= 0) {
    397 		HIST_ENTRY *rl_he;
    398 		rl_he = history_get(event_num);
    399 		if (!rl_he)
    400 			return 0;
    401 		event_data = rl_he->line;
    402 	} else
    403 		return -1;
    404 
    405 	if (cmd[idx] != ':')
    406 		return -1;
    407 	cmd += idx + 1;
    408 
    409 	/* recognize cmd */
    410 	if (*cmd == '^')
    411 		start = end = 1, cmd++;
    412 	else if (*cmd == '$')
    413 		start = end = -1, cmd++;
    414 	else if (*cmd == '*')
    415 		start = 1, end = -1, cmd++;
    416 	else if (isdigit((unsigned char) *cmd)) {
    417 		const char *temp;
    418 		int shifted = 0;
    419 
    420 		start = atoi(cmd);
    421 		temp = cmd;
    422 		for (; isdigit((unsigned char) *cmd); cmd++);
    423 		if (temp != cmd)
    424 			shifted = 1;
    425 		if (shifted && *cmd == '-') {
    426 			if (!isdigit((unsigned char) *(cmd + 1)))
    427 				end = -2;
    428 			else {
    429 				end = atoi(cmd + 1);
    430 				for (; isdigit((unsigned char) *cmd); cmd++);
    431 			}
    432 		} else if (shifted && *cmd == '*')
    433 			end = -1, cmd++;
    434 		else if (shifted)
    435 			end = start;
    436 	}
    437 	if (*cmd == ':')
    438 		cmd++;
    439 
    440 	line = strdup(event_data);
    441 	for (; *cmd; cmd++) {
    442 		if (*cmd == ':')
    443 			continue;
    444 		else if (*cmd == 'h')
    445 			h_on = 1 | g_on, g_on = 0;
    446 		else if (*cmd == 't')
    447 			t_on = 1 | g_on, g_on = 0;
    448 		else if (*cmd == 'r')
    449 			r_on = 1 | g_on, g_on = 0;
    450 		else if (*cmd == 'e')
    451 			e_on = 1 | g_on, g_on = 0;
    452 		else if (*cmd == 'p')
    453 			p_on = 1 | g_on, g_on = 0;
    454 		else if (*cmd == 'g')
    455 			g_on = 2;
    456 		else if (*cmd == 's' || *cmd == '&') {
    457 			char  *what, *with, delim;
    458 			int    len, from_len;
    459 			size_t size;
    460 
    461 			if (*cmd == '&' && (from == NULL || to == NULL))
    462 				continue;
    463 			else if (*cmd == 's') {
    464 				delim = *(++cmd), cmd++;
    465 				size = 16;
    466 				what = realloc(from, size);
    467 				len = 0;
    468 				for (; *cmd && *cmd != delim; cmd++) {
    469 					if (*cmd == '\\'
    470 					    && *(cmd + 1) == delim)
    471 						cmd++;
    472 					if (len >= size)
    473 						what = realloc(what,
    474 						    (size <<= 1));
    475 					what[len++] = *cmd;
    476 				}
    477 				what[len] = '\0';
    478 				from = what;
    479 				if (*what == '\0') {
    480 					free(what);
    481 					if (search)
    482 						from = strdup(search);
    483 					else {
    484 						from = NULL;
    485 						return -1;
    486 					}
    487 				}
    488 				cmd++;	/* shift after delim */
    489 				if (!*cmd)
    490 					continue;
    491 
    492 				size = 16;
    493 				with = realloc(to, size);
    494 				len = 0;
    495 				from_len = strlen(from);
    496 				for (; *cmd && *cmd != delim; cmd++) {
    497 					if (len + from_len + 1 >= size) {
    498 						size += from_len + 1;
    499 						with = realloc(with, size);
    500 					}
    501 					if (*cmd == '&') {
    502 						/* safe */
    503 						(void)strcpy(&with[len], from);
    504 						len += from_len;
    505 						continue;
    506 					}
    507 					if (*cmd == '\\'
    508 					    && (*(cmd + 1) == delim
    509 						|| *(cmd + 1) == '&'))
    510 						cmd++;
    511 					with[len++] = *cmd;
    512 				}
    513 				with[len] = '\0';
    514 				to = with;
    515 
    516 				tempcmd = _rl_compat_sub(line, from, to,
    517 				    (g_on) ? 1 : 0);
    518 				free(line);
    519 				line = tempcmd;
    520 				g_on = 0;
    521 			}
    522 		}
    523 	}
    524 
    525 	arr = history_tokenize(line);
    526 	free(line);		/* no more needed */
    527 	if (arr && *arr == NULL)
    528 		free(arr), arr = NULL;
    529 	if (!arr)
    530 		return -1;
    531 
    532 	/* find out max valid idx to array of array */
    533 	max = 0;
    534 	for (i = 0; arr[i]; i++)
    535 		max++;
    536 	max--;
    537 
    538 	/* set boundaries to something relevant */
    539 	if (start < 0)
    540 		start = 1;
    541 	if (end < 0)
    542 		end = max - ((end < -1) ? 1 : 0);
    543 
    544 	/* check boundaries ... */
    545 	if (start > max || end > max || start > end)
    546 		return -1;
    547 
    548 	for (i = 0; i <= max; i++) {
    549 		char           *temp;
    550 		if (h_on && (i == 1 || h_on > 1) &&
    551 		    (temp = strrchr(arr[i], '/')))
    552 			*(temp + 1) = '\0';
    553 		if (t_on && (i == 1 || t_on > 1) &&
    554 		    (temp = strrchr(arr[i], '/')))
    555 			(void)strcpy(arr[i], temp + 1);
    556 		if (r_on && (i == 1 || r_on > 1) &&
    557 		    (temp = strrchr(arr[i], '.')))
    558 			*temp = '\0';
    559 		if (e_on && (i == 1 || e_on > 1) &&
    560 		    (temp = strrchr(arr[i], '.')))
    561 			(void)strcpy(arr[i], temp);
    562 	}
    563 
    564 	cmdsize = 1, cmdlen = 0;
    565 	tempcmd = malloc(cmdsize);
    566 	for (i = start; start <= i && i <= end; i++) {
    567 		int             arr_len;
    568 
    569 		arr_len = strlen(arr[i]);
    570 		if (cmdlen + arr_len + 1 >= cmdsize) {
    571 			cmdsize += arr_len + 1;
    572 			tempcmd = realloc(tempcmd, cmdsize);
    573 		}
    574 		(void)strcpy(&tempcmd[cmdlen], arr[i]);	/* safe */
    575 		cmdlen += arr_len;
    576 		tempcmd[cmdlen++] = ' ';	/* add a space */
    577 	}
    578 	while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1]))
    579 		cmdlen--;
    580 	tempcmd[cmdlen] = '\0';
    581 
    582 	*result = tempcmd;
    583 
    584 	for (i = 0; i <= max; i++)
    585 		free(arr[i]);
    586 	free(arr), arr = (char **) NULL;
    587 	return (p_on) ? 2 : 1;
    588 }
    589 
    590 /*
    591  * csh-style history expansion
    592  */
    593 int
    594 history_expand(str, output)
    595 	char           *str;
    596 	char          **output;
    597 {
    598 	int             i, retval = 0, idx;
    599 	size_t		size;
    600 	char           *temp, *result;
    601 
    602 	if (h == NULL || e == NULL)
    603 		rl_initialize();
    604 
    605 	*output = strdup(str);	/* do it early */
    606 
    607 	if (str[0] == history_subst_char) {
    608 		/* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
    609 		temp = alloca(4 + strlen(str) + 1);
    610 		temp[0] = temp[1] = history_expansion_char;
    611 		temp[2] = ':';
    612 		temp[3] = 's';
    613 		(void)strcpy(temp + 4, str);
    614 		str = temp;
    615 	}
    616 #define ADD_STRING(what, len) 						\
    617 	{								\
    618 		if (idx + len + 1 > size)				\
    619 			result = realloc(result, (size += len + 1));	\
    620 		(void)strncpy(&result[idx], what, len);			\
    621 		idx += len;						\
    622 		result[idx] = '\0';					\
    623 	}
    624 
    625 	result = NULL;
    626 	size = idx = 0;
    627 	for (i = 0; str[i];) {
    628 		int start, j, loop_again;
    629 		size_t len;
    630 
    631 		loop_again = 1;
    632 		start = j = i;
    633 loop:
    634 		for (; str[j]; j++) {
    635 			if (str[j] == '\\' &&
    636 			    str[j + 1] == history_expansion_char) {
    637 				(void)strcpy(&str[j], &str[j + 1]);
    638 				continue;
    639 			}
    640 			if (!loop_again) {
    641 				if (str[j] == '?') {
    642 					while (str[j] && str[++j] != '?');
    643 					if (str[j] == '?')
    644 						j++;
    645 				} else if (isspace((unsigned char) str[j]))
    646 					break;
    647 			}
    648 			if (str[j] == history_expansion_char
    649 			    && !strchr(history_no_expand_chars, str[j + 1])
    650 			    && (!history_inhibit_expansion_function ||
    651 			(*history_inhibit_expansion_function) (str, j) == 0))
    652 				break;
    653 		}
    654 
    655 		if (str[j] && str[j + 1] != '#' && loop_again) {
    656 			i = j;
    657 			j++;
    658 			if (str[j] == history_expansion_char)
    659 				j++;
    660 			loop_again = 0;
    661 			goto loop;
    662 		}
    663 		len = i - start;
    664 		temp = &str[start];
    665 		ADD_STRING(temp, len);
    666 
    667 		if (str[i] == '\0' || str[i] != history_expansion_char
    668 		    || str[i + 1] == '#') {
    669 			len = j - i;
    670 			temp = &str[i];
    671 			ADD_STRING(temp, len);
    672 			if (start == 0)
    673 				retval = 0;
    674 			else
    675 				retval = 1;
    676 			break;
    677 		}
    678 		retval = _history_expand_command(&str[i], (size_t)(j - i),
    679 						 &temp);
    680 		if (retval != -1) {
    681 			len = strlen(temp);
    682 			ADD_STRING(temp, len);
    683 		}
    684 		i = j;
    685 	}			/* for(i ...) */
    686 
    687 	if (retval == 2) {
    688 		add_history(temp);
    689 #ifdef GDB_411_HACK
    690 		/* gdb 4.11 has been shipped with readline, where */
    691 		/* history_expand() returned -1 when the line	  */
    692 		/* should not be executed; in readline 2.1+	  */
    693 		/* it should return 2 in such a case		  */
    694 		retval = -1;
    695 #endif
    696 	}
    697 	free(*output);
    698 	*output = result;
    699 
    700 	return retval;
    701 }
    702 
    703 /*
    704  * returns array of tokens parsed out of string, much as the shell might
    705  */
    706 char **
    707 history_tokenize(str)
    708 	const char     *str;
    709 {
    710 	int  size = 1, result_idx = 0, i, start;
    711 	size_t len;
    712 	char **result = NULL, *temp, delim = '\0';
    713 
    714 	for (i = 0; str[i]; i++) {
    715 		while (isspace((unsigned char) str[i]))
    716 			i++;
    717 		start = i;
    718 		for (; str[i]; i++) {
    719 			if (str[i] == '\\')
    720 				i++;
    721 			else if (str[i] == delim)
    722 				delim = '\0';
    723 			else if (!delim &&
    724 			    (isspace((unsigned char) str[i]) ||
    725 			    strchr("()<>;&|$", str[i])))
    726 				break;
    727 			else if (!delim && strchr("'`\"", str[i]))
    728 				delim = str[i];
    729 		}
    730 
    731 		if (result_idx + 2 >= size) {
    732 			size <<= 1;
    733 			result = realloc(result, size * sizeof(char *));
    734 		}
    735 		len = i - start;
    736 		temp = malloc(len + 1);
    737 		(void)strncpy(temp, &str[start], len);
    738 		temp[len] = '\0';
    739 		result[result_idx++] = temp;
    740 		result[result_idx] = NULL;
    741 	}
    742 
    743 	return result;
    744 }
    745 
    746 /*
    747  * limit size of history record to ``max'' events
    748  */
    749 void
    750 stifle_history(max)
    751 	int max;
    752 {
    753 	HistEvent ev;
    754 
    755 	if (h == NULL || e == NULL)
    756 		rl_initialize();
    757 
    758 	if (history(h, &ev, H_SETSIZE, max) == 0)
    759 		max_input_history = max;
    760 }
    761 
    762 /*
    763  * "unlimit" size of history - set the limit to maximum allowed int value
    764  */
    765 int
    766 unstifle_history()
    767 {
    768 	HistEvent ev;
    769 	int omax;
    770 
    771 	history(h, &ev, H_SETSIZE, INT_MAX);
    772 	omax = max_input_history;
    773 	max_input_history = INT_MAX;
    774 	return omax;		/* some value _must_ be returned */
    775 }
    776 
    777 int
    778 history_is_stifled()
    779 {
    780 	/* cannot return true answer */
    781 	return (max_input_history != INT_MAX);
    782 }
    783 
    784 /*
    785  * read history from a file given
    786  */
    787 int
    788 read_history(filename)
    789 	const char *filename;
    790 {
    791 	HistEvent ev;
    792 
    793 	if (h == NULL || e == NULL)
    794 		rl_initialize();
    795 	return history(h, &ev, H_LOAD, filename);
    796 }
    797 
    798 /*
    799  * write history to a file given
    800  */
    801 int
    802 write_history(filename)
    803 	const char *filename;
    804 {
    805 	HistEvent ev;
    806 
    807 	if (h == NULL || e == NULL)
    808 		rl_initialize();
    809 	return history(h, &ev, H_SAVE, filename);
    810 }
    811 
    812 /*
    813  * returns history ``num''th event
    814  *
    815  * returned pointer points to static variable
    816  */
    817 HIST_ENTRY *
    818 history_get(num)
    819 	int             num;
    820 {
    821 	static HIST_ENTRY she;
    822 	HistEvent ev;
    823 	int i = 1, curr_num;
    824 
    825 	if (h == NULL || e == NULL)
    826 		rl_initialize();
    827 
    828 	/* rewind to beginning */
    829 	if (history(h, &ev, H_CURR) != 0)
    830 		return NULL;
    831 	curr_num = ev.num;
    832 	if (history(h, &ev, H_LAST) != 0)
    833 		return NULL;	/* error */
    834 	while (i < num && history(h, &ev, H_PREV) == 0)
    835 		i++;
    836 	if (i != num)
    837 		return NULL;	/* not so many entries */
    838 
    839 	she.line = ev.str;
    840 	she.data = NULL;
    841 
    842 	/* rewind history to the same event it was before */
    843 	(void) history(h, &ev, H_FIRST);
    844 	(void) history(h, &ev, H_NEXT_EVENT, curr_num);
    845 
    846 	return &she;
    847 }
    848 
    849 /*
    850  * add the line to history table
    851  */
    852 int
    853 add_history(line)
    854 	const char *line;
    855 {
    856 	HistEvent ev;
    857 
    858 	if (h == NULL || e == NULL)
    859 		rl_initialize();
    860 
    861 	(void) history(h, &ev, H_ENTER, line);
    862 	if (history(h, &ev, H_GETSIZE) == 0)
    863 		history_length = ev.num;
    864 
    865 	return (!(history_length > 0));	/* return 0 if all is okay */
    866 }
    867 
    868 /*
    869  * clear the history list - delete all entries
    870  */
    871 void
    872 clear_history()
    873 {
    874 	HistEvent ev;
    875 	history(h, &ev, H_CLEAR);
    876 }
    877 
    878 /*
    879  * returns offset of the current history event
    880  */
    881 int
    882 where_history()
    883 {
    884 	HistEvent ev;
    885 	int curr_num, off;
    886 
    887 	if (history(h, &ev, H_CURR) != 0)
    888 		return 0;
    889 	curr_num = ev.num;
    890 
    891 	history(h, &ev, H_FIRST);
    892 	off = 1;
    893 	while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0)
    894 		off++;
    895 
    896 	return off;
    897 }
    898 
    899 /*
    900  * returns current history event or NULL if there is no such event
    901  */
    902 HIST_ENTRY *
    903 current_history()
    904 {
    905 	return _move_history(H_CURR);
    906 }
    907 
    908 /*
    909  * returns total number of bytes history events' data are using
    910  */
    911 int
    912 history_total_bytes()
    913 {
    914 	HistEvent ev;
    915 	int curr_num, size;
    916 
    917 	if (history(h, &ev, H_CURR) != 0)
    918 		return -1;
    919 	curr_num = ev.num;
    920 
    921 	history(h, &ev, H_FIRST);
    922 	size = 0;
    923 	do
    924 		size += strlen(ev.str);
    925 	while (history(h, &ev, H_NEXT) == 0);
    926 
    927 	/* get to the same position as before */
    928 	history(h, &ev, H_PREV_EVENT, curr_num);
    929 
    930 	return size;
    931 }
    932 
    933 /*
    934  * sets the position in the history list to ``pos''
    935  */
    936 int
    937 history_set_pos(pos)
    938 	int pos;
    939 {
    940 	HistEvent ev;
    941 	int off, curr_num;
    942 
    943 	if (pos > history_length || pos < 0)
    944 		return -1;
    945 
    946 	history(h, &ev, H_CURR);
    947 	curr_num = ev.num;
    948 	history(h, &ev, H_FIRST);
    949 	off = 0;
    950 	while (off < pos && history(h, &ev, H_NEXT) == 0)
    951 		off++;
    952 
    953 	if (off != pos) {	/* do a rollback in case of error */
    954 		history(h, &ev, H_FIRST);
    955 		history(h, &ev, H_NEXT_EVENT, curr_num);
    956 		return -1;
    957 	}
    958 	return 0;
    959 }
    960 
    961 /*
    962  * returns previous event in history and shifts pointer accordingly
    963  */
    964 HIST_ENTRY *
    965 previous_history()
    966 {
    967 	return _move_history(H_PREV);
    968 }
    969 
    970 /*
    971  * returns next event in history and shifts pointer accordingly
    972  */
    973 HIST_ENTRY *
    974 next_history()
    975 {
    976 	return _move_history(H_NEXT);
    977 }
    978 
    979 /*
    980  * generic history search function
    981  */
    982 static int
    983 _history_search_gen(str, direction, pos)
    984 	const char *str;
    985 	int direction, pos;
    986 {
    987 	HistEvent       ev;
    988 	const char     *strp;
    989 	int             curr_num;
    990 
    991 	if (history(h, &ev, H_CURR) != 0)
    992 		return -1;
    993 	curr_num = ev.num;
    994 
    995 	for (;;) {
    996 		strp = strstr(ev.str, str);
    997 		if (strp && (pos < 0 || &ev.str[pos] == strp))
    998 			return (int) (strp - ev.str);
    999 		if (history(h, &ev, direction < 0 ? H_PREV : H_NEXT) != 0)
   1000 			break;
   1001 	}
   1002 
   1003 	history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
   1004 
   1005 	return -1;
   1006 }
   1007 
   1008 /*
   1009  * searches for first history event containing the str
   1010  */
   1011 int
   1012 history_search(str, direction)
   1013 	const char     *str;
   1014 	int             direction;
   1015 {
   1016 	return _history_search_gen(str, direction, -1);
   1017 }
   1018 
   1019 /*
   1020  * searches for first history event beginning with str
   1021  */
   1022 int
   1023 history_search_prefix(str, direction)
   1024 	const char     *str;
   1025 	int             direction;
   1026 {
   1027 	return _history_search_gen(str, direction, 0);
   1028 }
   1029 
   1030 /*
   1031  * search for event in history containing str, starting at offset
   1032  * abs(pos); continue backward, if pos<0, forward otherwise
   1033  */
   1034 /* ARGSUSED */
   1035 int
   1036 history_search_pos(str, direction, pos)
   1037 	const char     *str;
   1038 	int             direction, pos;
   1039 {
   1040 	HistEvent       ev;
   1041 	int             curr_num, off;
   1042 
   1043 	off = (pos > 0) ? pos : -pos;
   1044 	pos = (pos > 0) ? 1 : -1;
   1045 
   1046 	if (history(h, &ev, H_CURR) != 0)
   1047 		return -1;
   1048 	curr_num = ev.num;
   1049 
   1050 	if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0)
   1051 		return -1;
   1052 
   1053 
   1054 	for (;;) {
   1055 		if (strstr(ev.str, str))
   1056 			return off;
   1057 		if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0)
   1058 			break;
   1059 	}
   1060 
   1061 	/* set "current" pointer back to previous state */
   1062 	history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
   1063 
   1064 	return -1;
   1065 }
   1066 
   1067 
   1068 /********************************/
   1069 /* completition functions	 */
   1070 
   1071 /*
   1072  * does tilde expansion of strings of type ``~user/foo''
   1073  * if ``user'' isn't valid user name or ``txt'' doesn't start
   1074  * w/ '~', returns pointer to strdup()ed copy of ``txt''
   1075  *
   1076  * it's callers's responsibility to free() returned string
   1077  */
   1078 char *
   1079 tilde_expand(txt)
   1080 	char     *txt;
   1081 {
   1082 	struct passwd  *pass;
   1083 	char           *temp;
   1084 	size_t          len = 0;
   1085 
   1086 	if (txt[0] != '~')
   1087 		return strdup(txt);
   1088 
   1089 	temp = strchr(txt + 1, '/');
   1090 	if (temp == NULL)
   1091 		temp = strdup(txt + 1);
   1092 	else {
   1093 		len = temp - txt + 1;	/* text until string after slash */
   1094 		temp = malloc(len);
   1095 		(void)strncpy(temp, txt + 1, len - 2);
   1096 		temp[len - 2] = '\0';
   1097 	}
   1098 	pass = getpwnam(temp);
   1099 	free(temp);		/* value no more needed */
   1100 	if (pass == NULL)
   1101 		return strdup(txt);
   1102 
   1103 	/* update pointer txt to point at string immedially following */
   1104 	/* first slash */
   1105 	txt += len;
   1106 
   1107 	temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1);
   1108 	(void)sprintf(temp, "%s/%s", pass->pw_dir, txt);
   1109 
   1110 	return temp;
   1111 }
   1112 
   1113 /*
   1114  * return first found file name starting by the ``text'' or NULL if no
   1115  * such file can be found
   1116  * value of ``state'' is ignored
   1117  *
   1118  * it's caller's responsibility to free returned string
   1119  */
   1120 char           *
   1121 filename_completion_function(text, state)
   1122 	const char     *text;
   1123 	int             state;
   1124 {
   1125 	static DIR     *dir = NULL;
   1126 	static char    *filename = NULL, *dirname = NULL;
   1127 	static size_t   filename_len = 0;
   1128 	struct dirent  *entry;
   1129 	char           *temp;
   1130 	size_t          len;
   1131 
   1132 	if (state == 0 || dir == NULL) {
   1133 		if (dir != NULL) {
   1134 			closedir(dir);
   1135 			dir = NULL;
   1136 		}
   1137 		temp = strrchr(text, '/');
   1138 		if (temp) {
   1139 			temp++;
   1140 			filename = realloc(filename, strlen(temp) + 1);
   1141 			(void)strcpy(filename, temp);
   1142 			len = temp - text;	/* including last slash */
   1143 			dirname = realloc(dirname, len + 1);
   1144 			(void)strncpy(dirname, text, len);
   1145 			dirname[len] = '\0';
   1146 		} else {
   1147 			filename = strdup(text);
   1148 			dirname = NULL;
   1149 		}
   1150 
   1151 		/* support for ``~user'' syntax */
   1152 		if (dirname && *dirname == '~') {
   1153 			temp = tilde_expand(dirname);
   1154 			dirname = realloc(dirname, strlen(temp) + 1);
   1155 			(void)strcpy(dirname, temp);	/* safe */
   1156 			free(temp);	/* no more needed */
   1157 		}
   1158 		/* will be used in cycle */
   1159 		filename_len = strlen(filename);
   1160 		if (filename_len == 0)
   1161 			return NULL;	/* no expansion possible */
   1162 
   1163 		dir = opendir(dirname ? dirname : ".");
   1164 		if (!dir)
   1165 			return NULL;	/* cannot open the directory */
   1166 	}
   1167 	/* find the match */
   1168 	while ((entry = readdir(dir)) != NULL) {
   1169 		/* otherwise, get first entry where first */
   1170 		/* filename_len characters are equal	  */
   1171 		if (entry->d_name[0] == filename[0]
   1172 #if defined(__SVR4) || defined(__linux__)
   1173 		    && strlen(entry->d_name) >= filename_len
   1174 #else
   1175 		    && entry->d_namlen >= filename_len
   1176 #endif
   1177 		    && strncmp(entry->d_name, filename,
   1178 			       filename_len) == 0)
   1179 			break;
   1180 	}
   1181 
   1182 	if (entry) {		/* match found */
   1183 
   1184 		struct stat     stbuf;
   1185 #if defined(__SVR4) || defined(__linux__)
   1186 		len = strlen(entry->d_name) +
   1187 #else
   1188 		len = entry->d_namlen +
   1189 #endif
   1190 			((dirname) ? strlen(dirname) : 0) + 1 + 1;
   1191 		temp = malloc(len);
   1192 		(void)sprintf(temp, "%s%s",
   1193 			dirname ? dirname : "", entry->d_name);	/* safe */
   1194 
   1195 		/* test, if it's directory */
   1196 		if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode))
   1197 			strcat(temp, "/");	/* safe */
   1198 	} else
   1199 		temp = NULL;
   1200 
   1201 	return temp;
   1202 }
   1203 
   1204 /*
   1205  * a completion generator for usernames; returns _first_ username
   1206  * which starts with supplied text
   1207  * text contains a partial username preceded by random character
   1208  * (usually '~'); state is ignored
   1209  * it's callers responsibility to free returned value
   1210  */
   1211 char           *
   1212 username_completion_function(text, state)
   1213 	const char     *text;
   1214 	int             state;
   1215 {
   1216 	struct passwd  *pwd;
   1217 
   1218 	if (text[0] == '\0')
   1219 		return NULL;
   1220 
   1221 	if (*text == '~')
   1222 		text++;
   1223 
   1224 	if (state == 0)
   1225 		setpwent();
   1226 
   1227 	while ((pwd = getpwent()) && text[0] == pwd->pw_name[0]
   1228 	       && strcmp(text, pwd->pw_name) == 0);
   1229 
   1230 	if (pwd == NULL) {
   1231 		endpwent();
   1232 		return NULL;
   1233 	}
   1234 	return strdup(pwd->pw_name);
   1235 }
   1236 
   1237 /*
   1238  * el-compatible wrapper around rl_complete; needed for key binding
   1239  */
   1240 /* ARGSUSED */
   1241 static unsigned char
   1242 _el_rl_complete(el, ch)
   1243 	EditLine       *el;
   1244 	int             ch;
   1245 {
   1246 	return (unsigned char) rl_complete(0, ch);
   1247 }
   1248 
   1249 /*
   1250  * returns list of completitions for text given
   1251  */
   1252 char          **
   1253 completion_matches(text, genfunc)
   1254 	const char     *text;
   1255 	CPFunction     *genfunc;
   1256 {
   1257 	char          **match_list = NULL, *retstr, *prevstr;
   1258 	size_t          math_list_len, max_equal, which, i;
   1259 	int		matches;
   1260 
   1261 	if (h == NULL || e == NULL)
   1262 		rl_initialize();
   1263 
   1264 	matches = 0;
   1265 	math_list_len = 1;
   1266 	while ((retstr = (*genfunc) (text, matches)) != NULL) {
   1267 		if (matches + 1 >= math_list_len) {
   1268 			math_list_len <<= 1;
   1269 			match_list = realloc(match_list,
   1270 			    math_list_len * sizeof(char *));
   1271 		}
   1272 		match_list[++matches] = retstr;
   1273 	}
   1274 
   1275 	if (!match_list)
   1276 		return (char **) NULL;	/* nothing found */
   1277 
   1278 	/* find least denominator and insert it to match_list[0] */
   1279 	which = 2;
   1280 	prevstr = match_list[1];
   1281 	max_equal = strlen(prevstr);
   1282 	for (; which < matches; which++) {
   1283 		for (i = 0; i < max_equal &&
   1284 		    prevstr[i] == match_list[which][i]; i++)
   1285 			continue;
   1286 		max_equal = i;
   1287 	}
   1288 
   1289 	retstr = malloc(max_equal + 1);
   1290 	(void)strncpy(retstr, match_list[1], max_equal);
   1291 	retstr[max_equal] = '\0';
   1292 	match_list[0] = retstr;
   1293 
   1294 	/* add NULL as last pointer to the array */
   1295 	if (matches + 1 >= math_list_len)
   1296 		match_list = realloc(match_list,
   1297 		    (math_list_len + 1) * sizeof(char *));
   1298 	match_list[matches + 1] = (char *) NULL;
   1299 
   1300 	return match_list;
   1301 }
   1302 
   1303 /*
   1304  * called by rl_complete()
   1305  */
   1306 /* ARGSUSED */
   1307 static int
   1308 rl_complete_internal(what_to_do)
   1309 	int             what_to_do;
   1310 {
   1311 	CPFunction     *complet_func;
   1312 	const LineInfo *li;
   1313 	char           *temp, *temp2, **arr;
   1314 	size_t          len;
   1315 
   1316 	if (h == NULL || e == NULL)
   1317 		rl_initialize();
   1318 
   1319 	complet_func = rl_completion_entry_function;
   1320 	if (!complet_func)
   1321 		complet_func = filename_completion_function;
   1322 
   1323 	li = el_line(e);
   1324 	/* LINTED const cast */
   1325 	temp = (char *) li->cursor;
   1326 	while (temp > li->buffer &&
   1327 	    !strchr(rl_basic_word_break_characters, *(temp - 1)))
   1328 		temp--;
   1329 
   1330 	len = li->cursor - temp;
   1331 	temp2 = alloca(len + 1);
   1332 	(void)strncpy(temp2, temp, len);
   1333 	temp = temp2;
   1334 	temp[len] = '\0';
   1335 
   1336 	/* these can be used by function called in completion_matches() */
   1337 	/* or (*rl_attempted_completion_function)() */
   1338 	rl_point = li->cursor - li->buffer;
   1339 	rl_end = li->lastchar - li->buffer;
   1340 
   1341 	if (!rl_attempted_completion_function)
   1342 		arr = completion_matches(temp, complet_func);
   1343 	else {
   1344 		int             end = li->cursor - li->buffer;
   1345 		arr = (*rl_attempted_completion_function) (temp, (int)
   1346 							   (end - len), end);
   1347 	}
   1348 	free(temp);		/* no more needed */
   1349 
   1350 	if (arr) {
   1351 		int             i;
   1352 
   1353 		el_deletestr(e, (int)len);
   1354 		el_insertstr(e, arr[0]);
   1355 		if (strcmp(arr[0], arr[1]) == 0) {
   1356 			/* lcd is valid object, so add a space to mark it */
   1357 			/* in case of filename completition, add a space  */
   1358 			/* only if object found is not directory	  */
   1359 			size_t alen = strlen(arr[0]);
   1360 			if (complet_func != filename_completion_function
   1361 			    || (alen > 0 && (arr[0])[alen - 1] != '/'))
   1362 				el_insertstr(e, " ");
   1363 		} else
   1364 			/* lcd is not a valid object - further specification */
   1365 			/* is needed */
   1366 			el_beep(e);
   1367 
   1368 		/* free elements of array and the array itself */
   1369 		for (i = 0; arr[i]; i++)
   1370 			free(arr[i]);
   1371 		free(arr), arr = NULL;
   1372 
   1373 		return CC_REFRESH;
   1374 	}
   1375 	return CC_NORM;
   1376 }
   1377 
   1378 /*
   1379  * complete word at current point
   1380  */
   1381 int
   1382 rl_complete(ignore, invoking_key)
   1383 	int             ignore, invoking_key;
   1384 {
   1385 	if (h == NULL || e == NULL)
   1386 		rl_initialize();
   1387 
   1388 	if (rl_inhibit_completion) {
   1389 		rl_insert(ignore, invoking_key);
   1390 		return CC_REFRESH;
   1391 	} else
   1392 		return rl_complete_internal(invoking_key);
   1393 }
   1394 
   1395 /*
   1396  * misc other functions
   1397  */
   1398 
   1399 /*
   1400  * bind key c to readline-type function func
   1401  */
   1402 int
   1403 rl_bind_key(c, func)
   1404 	int             c;
   1405 	int func        __P((int, int));
   1406 {
   1407 	int             retval = -1;
   1408 
   1409 	if (h == NULL || e == NULL)
   1410 		rl_initialize();
   1411 
   1412 	if (func == rl_insert) {
   1413 		/* XXX notice there is no range checking of ``c'' */
   1414 		e->el_map.key[c] = ED_INSERT;
   1415 		retval = 0;
   1416 	}
   1417 	return retval;
   1418 }
   1419 
   1420 /*
   1421  * read one key from input - handles chars pushed back
   1422  * to input stream also
   1423  */
   1424 int
   1425 rl_read_key()
   1426 {
   1427 	char            fooarr[2 * sizeof(int)];
   1428 
   1429 	if (e == NULL || h == NULL)
   1430 		rl_initialize();
   1431 
   1432 	return el_getc(e, fooarr);
   1433 }
   1434 
   1435 /*
   1436  * reset the terminal
   1437  */
   1438 /* ARGSUSED */
   1439 void
   1440 rl_reset_terminal(p)
   1441 	const char     *p;
   1442 {
   1443 	if (h == NULL || e == NULL)
   1444 		rl_initialize();
   1445 	el_reset(e);
   1446 }
   1447 
   1448 /*
   1449  * insert character ``c'' back into input stream, ``count'' times
   1450  */
   1451 int
   1452 rl_insert(count, c)
   1453 	int             count, c;
   1454 {
   1455 	char            arr[2];
   1456 
   1457 	if (h == NULL || e == NULL)
   1458 		rl_initialize();
   1459 
   1460 	/* XXX - int -> char conversion can lose on multichars */
   1461 	arr[0] = c;
   1462 	arr[1] = '\0';
   1463 
   1464 	for (; count > 0; count--)
   1465 		el_push(e, arr);
   1466 
   1467 	return 0;
   1468 }
   1469