1/*	$NetBSD: readline.c,v 1.178 2022/12/02 19:23:15 christos 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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "config.h"
33#if !defined(lint) && !defined(SCCSID)
34__RCSID("$NetBSD: readline.c,v 1.178 2022/12/02 19:23:15 christos Exp $");
35#endif /* not lint && not SCCSID */
36
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <ctype.h>
40#include <dirent.h>
41#include <errno.h>
42#include <fcntl.h>
43#include <limits.h>
44#include <pwd.h>
45#include <setjmp.h>
46#include <stdarg.h>
47#include <stdint.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
52#include <vis.h>
53
54#include "readline/readline.h"
55#include "el.h"
56#include "fcns.h"
57#include "filecomplete.h"
58
59void rl_prep_terminal(int);
60void rl_deprep_terminal(void);
61
62/* for rl_complete() */
63#define TAB		'\r'
64
65/* see comment at the #ifdef for sense of this */
66/* #define GDB_411_HACK */
67
68/* readline compatibility stuff - look at readline sources/documentation */
69/* to see what these variables mean */
70const char *rl_library_version = "EditLine wrapper";
71int rl_readline_version = RL_READLINE_VERSION;
72static char empty[] = { '\0' };
73static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' };
74static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$',
75    '>', '<', '=', ';', '|', '&', '{', '(', '\0' };
76const char *rl_readline_name = empty;
77FILE *rl_instream = NULL;
78FILE *rl_outstream = NULL;
79int rl_point = 0;
80int rl_end = 0;
81char *rl_line_buffer = NULL;
82rl_vcpfunc_t *rl_linefunc = NULL;
83int rl_done = 0;
84rl_hook_func_t *rl_event_hook = NULL;
85KEYMAP_ENTRY_ARRAY emacs_standard_keymap,
86    emacs_meta_keymap,
87    emacs_ctlx_keymap;
88/*
89 * The following is not implemented; we always catch signals in the
90 * libedit fashion: set handlers on entry to el_gets() and clear them
91 * on the way out. This simplistic approach works for most cases; if
92 * it does not work for your application, please let us know.
93 */
94int rl_catch_signals = 1;
95int rl_catch_sigwinch = 1;
96
97int history_base = 1;		/* probably never subject to change */
98int history_length = 0;
99int history_offset = 0;
100int max_input_history = 0;
101char history_expansion_char = '!';
102char history_subst_char = '^';
103char *history_no_expand_chars = expand_chars;
104Function *history_inhibit_expansion_function = NULL;
105char *history_arg_extract(int start, int end, const char *str);
106
107int rl_inhibit_completion = 0;
108int rl_attempted_completion_over = 0;
109const char *rl_basic_word_break_characters = break_chars;
110char *rl_completer_word_break_characters = NULL;
111const char *rl_completer_quote_characters = NULL;
112const char *rl_basic_quote_characters = "\"'";
113rl_compentry_func_t *rl_completion_entry_function = NULL;
114char *(*rl_completion_word_break_hook)(void) = NULL;
115rl_completion_func_t *rl_attempted_completion_function = NULL;
116rl_hook_func_t *rl_pre_input_hook = NULL;
117rl_hook_func_t *rl_startup1_hook = NULL;
118int (*rl_getc_function)(FILE *) = NULL;
119char *rl_terminal_name = NULL;
120int rl_already_prompted = 0;
121int rl_filename_completion_desired = 0;
122int rl_ignore_completion_duplicates = 0;
123int readline_echoing_p = 1;
124int _rl_print_completions_horizontally = 0;
125VFunction *rl_redisplay_function = NULL;
126rl_hook_func_t *rl_startup_hook = NULL;
127VFunction *rl_completion_display_matches_hook = NULL;
128VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal;
129VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal;
130KEYMAP_ENTRY_ARRAY emacs_meta_keymap;
131unsigned long rl_readline_state = RL_STATE_NONE;
132int _rl_complete_mark_directories;
133rl_icppfunc_t *rl_directory_completion_hook;
134int rl_completion_suppress_append;
135int rl_sort_completion_matches;
136int _rl_completion_prefix_display_length;
137int _rl_echoing_p;
138int history_max_entries;
139char *rl_display_prompt;
140int rl_erase_empty_line;
141
142/*
143 * The current prompt string.
144 */
145char *rl_prompt = NULL;
146char *rl_prompt_saved = NULL;
147/*
148 * This is set to character indicating type of completion being done by
149 * rl_complete_internal(); this is available for application completion
150 * functions.
151 */
152int rl_completion_type = 0;
153
154/*
155 * If more than this number of items results from query for possible
156 * completions, we ask user if they are sure to really display the list.
157 */
158int rl_completion_query_items = 100;
159
160/*
161 * List of characters which are word break characters, but should be left
162 * in the parsed text when it is passed to the completion function.
163 * Shell uses this to help determine what kind of completing to do.
164 */
165const char *rl_special_prefixes = NULL;
166
167/*
168 * This is the character appended to the completed words if at the end of
169 * the line. Default is ' ' (a space).
170 */
171int rl_completion_append_character = ' ';
172
173/* stuff below is used internally by libedit for readline emulation */
174
175static History *h = NULL;
176static EditLine *e = NULL;
177static rl_command_func_t *map[256];
178static jmp_buf topbuf;
179
180/* internal functions */
181static unsigned char	 _el_rl_complete(EditLine *, int);
182static unsigned char	 _el_rl_tstp(EditLine *, int);
183static char		*_get_prompt(EditLine *);
184static int		 _getc_function(EditLine *, wchar_t *);
185static int		 _history_expand_command(const char *, size_t, size_t,
186    char **);
187static char		*_rl_compat_sub(const char *, const char *,
188    const char *, int);
189static int		 _rl_event_read_char(EditLine *, wchar_t *);
190static void		 _rl_update_pos(void);
191
192static HIST_ENTRY rl_he;
193
194/* ARGSUSED */
195static char *
196_get_prompt(EditLine *el __attribute__((__unused__)))
197{
198	rl_already_prompted = 1;
199	return rl_prompt;
200}
201
202
203/*
204 * read one key from user defined input function
205 */
206static int
207/*ARGSUSED*/
208_getc_function(EditLine *el __attribute__((__unused__)), wchar_t *c)
209{
210	int i;
211
212	i = (*rl_getc_function)(rl_instream);
213	if (i == -1)
214		return 0;
215	*c = (wchar_t)i;
216	return 1;
217}
218
219static void
220_resize_fun(EditLine *el, void *a)
221{
222	const LineInfo *li;
223	const char **ap = a;
224
225	li = el_line(el);
226	*ap = li->buffer;
227}
228
229static const char *
230_default_history_file(void)
231{
232	struct passwd *p;
233	static char *path;
234	size_t len;
235
236	if (path)
237		return path;
238
239	if ((p = getpwuid(getuid())) == NULL)
240		return NULL;
241
242	len = strlen(p->pw_dir) + sizeof("/.history");
243	if ((path = el_malloc(len)) == NULL)
244		return NULL;
245
246	(void)snprintf(path, len, "%s/.history", p->pw_dir);
247	return path;
248}
249
250/*
251 * READLINE compatibility stuff
252 */
253
254/*
255 * Set the prompt
256 */
257int
258rl_set_prompt(const char *prompt)
259{
260	char *p;
261
262	if (!prompt)
263		prompt = "";
264	if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0)
265		return 0;
266	if (rl_prompt)
267		el_free(rl_prompt);
268	rl_prompt = strdup(prompt);
269	if (rl_prompt == NULL)
270		return -1;
271
272	while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) {
273		/* Remove adjacent end/start markers to avoid double-escapes. */
274		if (p[1] == RL_PROMPT_START_IGNORE) {
275			memmove(p, p + 2, 1 + strlen(p + 2));
276		} else {
277			*p = RL_PROMPT_START_IGNORE;
278		}
279	}
280
281	return 0;
282}
283
284void
285rl_save_prompt(void)
286{
287	rl_prompt_saved = strdup(rl_prompt);
288}
289
290void
291rl_restore_prompt(void)
292{
293	if (!rl_prompt_saved)
294		return;
295	rl_prompt = rl_prompt_saved;
296	rl_prompt_saved = NULL;
297}
298
299/*
300 * initialize rl compat stuff
301 */
302int
303rl_initialize(void)
304{
305	HistEvent ev;
306	int editmode = 1;
307	struct termios t;
308
309	if (e != NULL)
310		el_end(e);
311	if (h != NULL)
312		history_end(h);
313
314	RL_UNSETSTATE(RL_STATE_DONE);
315
316	if (!rl_instream)
317		rl_instream = stdin;
318	if (!rl_outstream)
319		rl_outstream = stdout;
320
321	/*
322	 * See if we don't really want to run the editor
323	 */
324	if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0)
325		editmode = 0;
326
327	e = el_init_internal(rl_readline_name, rl_instream, rl_outstream,
328	    stderr, fileno(rl_instream), fileno(rl_outstream), fileno(stderr),
329	    NO_RESET);
330
331	if (!editmode)
332		el_set(e, EL_EDITMODE, 0);
333
334	h = history_init();
335	if (!e || !h)
336		return -1;
337
338	history(h, &ev, H_SETSIZE, INT_MAX);	/* unlimited */
339	history_length = 0;
340	max_input_history = INT_MAX;
341	el_set(e, EL_HIST, history, h);
342
343	/* Setup resize function */
344	el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer);
345
346	/* setup getc function if valid */
347	if (rl_getc_function)
348		el_set(e, EL_GETCFN, _getc_function);
349
350	/* for proper prompt printing in readline() */
351	if (rl_set_prompt("") == -1) {
352		history_end(h);
353		el_end(e);
354		return -1;
355	}
356	el_set(e, EL_PROMPT_ESC, _get_prompt, RL_PROMPT_START_IGNORE);
357	el_set(e, EL_SIGNAL, rl_catch_signals);
358
359	/* set default mode to "emacs"-style and read setting afterwards */
360	/* so this can be overridden */
361	el_set(e, EL_EDITOR, "emacs");
362	if (rl_terminal_name != NULL)
363		el_set(e, EL_TERMINAL, rl_terminal_name);
364	else
365		el_get(e, EL_TERMINAL, &rl_terminal_name);
366
367	/*
368	 * Word completion - this has to go AFTER rebinding keys
369	 * to emacs-style.
370	 */
371	el_set(e, EL_ADDFN, "rl_complete",
372	    "ReadLine compatible completion function",
373	    _el_rl_complete);
374	el_set(e, EL_BIND, "^I", "rl_complete", NULL);
375
376	/*
377	 * Send TSTP when ^Z is pressed.
378	 */
379	el_set(e, EL_ADDFN, "rl_tstp",
380	    "ReadLine compatible suspend function",
381	    _el_rl_tstp);
382	el_set(e, EL_BIND, "^Z", "rl_tstp", NULL);
383
384	/*
385	 * Set some readline compatible key-bindings.
386	 */
387	el_set(e, EL_BIND, "^R", "em-inc-search-prev", NULL);
388
389	/*
390	 * Allow the use of Home/End keys.
391	 */
392	el_set(e, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
393	el_set(e, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
394	el_set(e, EL_BIND, "\\e[7~", "ed-move-to-beg", NULL);
395	el_set(e, EL_BIND, "\\e[8~", "ed-move-to-end", NULL);
396	el_set(e, EL_BIND, "\\e[H", "ed-move-to-beg", NULL);
397	el_set(e, EL_BIND, "\\e[F", "ed-move-to-end", NULL);
398
399	/*
400	 * Allow the use of the Delete/Insert keys.
401	 */
402	el_set(e, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
403	el_set(e, EL_BIND, "\\e[2~", "ed-quoted-insert", NULL);
404
405	/*
406	 * Ctrl-left-arrow and Ctrl-right-arrow for word moving.
407	 */
408	el_set(e, EL_BIND, "\\e[1;5C", "em-next-word", NULL);
409	el_set(e, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL);
410	el_set(e, EL_BIND, "\\e[5C", "em-next-word", NULL);
411	el_set(e, EL_BIND, "\\e[5D", "ed-prev-word", NULL);
412	el_set(e, EL_BIND, "\\e\\e[C", "em-next-word", NULL);
413	el_set(e, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL);
414
415	/* read settings from configuration file */
416	el_source(e, NULL);
417
418	/*
419	 * Unfortunately, some applications really do use rl_point
420	 * and rl_line_buffer directly.
421	 */
422	_resize_fun(e, &rl_line_buffer);
423	_rl_update_pos();
424
425	tty_end(e, TCSADRAIN);
426
427	return 0;
428}
429
430
431/*
432 * read one line from input stream and return it, chomping
433 * trailing newline (if there is any)
434 */
435char *
436readline(const char *p)
437{
438	HistEvent ev;
439	const char * volatile prompt = p;
440	int count;
441	const char *ret;
442	char *buf;
443	static int used_event_hook;
444
445	if (e == NULL || h == NULL)
446		rl_initialize();
447	if (rl_startup_hook) {
448		(*rl_startup_hook)();
449	}
450	tty_init(e);
451
452
453	rl_done = 0;
454
455	(void)setjmp(topbuf);
456	buf = NULL;
457
458	/* update prompt accordingly to what has been passed */
459	if (rl_set_prompt(prompt) == -1)
460		goto out;
461
462	if (rl_pre_input_hook)
463		(*rl_pre_input_hook)();
464
465	if (rl_event_hook && !(e->el_flags & NO_TTY)) {
466		el_set(e, EL_GETCFN, _rl_event_read_char);
467		used_event_hook = 1;
468	}
469
470	if (!rl_event_hook && used_event_hook) {
471		el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN);
472		used_event_hook = 0;
473	}
474
475	rl_already_prompted = 0;
476
477	/* get one line from input stream */
478	ret = el_gets(e, &count);
479
480	if (ret && count > 0) {
481		int lastidx;
482
483		buf = strdup(ret);
484		if (buf == NULL)
485			goto out;
486		lastidx = count - 1;
487		if (buf[lastidx] == '\n')
488			buf[lastidx] = '\0';
489	} else
490		buf = NULL;
491
492	history(h, &ev, H_GETSIZE);
493	history_length = ev.num;
494
495out:
496	tty_end(e, TCSADRAIN);
497	return buf;
498}
499
500/*
501 * history functions
502 */
503
504/*
505 * is normally called before application starts to use
506 * history expansion functions
507 */
508void
509using_history(void)
510{
511	if (h == NULL || e == NULL)
512		rl_initialize();
513	history_offset = history_length;
514}
515
516
517/*
518 * substitute ``what'' with ``with'', returning resulting string; if
519 * globally == 1, substitutes all occurrences of what, otherwise only the
520 * first one
521 */
522static char *
523_rl_compat_sub(const char *str, const char *what, const char *with,
524    int globally)
525{
526	const	char	*s;
527	char	*r, *result;
528	size_t	len, with_len, what_len;
529
530	len = strlen(str);
531	with_len = strlen(with);
532	what_len = strlen(what);
533
534	/* calculate length we need for result */
535	s = str;
536	while (*s) {
537		if (*s == *what && !strncmp(s, what, what_len)) {
538			len += with_len - what_len;
539			if (!globally)
540				break;
541			s += what_len;
542		} else
543			s++;
544	}
545	r = result = el_calloc(len + 1, sizeof(*r));
546	if (result == NULL)
547		return NULL;
548	s = str;
549	while (*s) {
550		if (*s == *what && !strncmp(s, what, what_len)) {
551			memcpy(r, with, with_len);
552			r += with_len;
553			s += what_len;
554			if (!globally) {
555				(void)strcpy(r, s);
556				return result;
557			}
558		} else
559			*r++ = *s++;
560	}
561	*r = '\0';
562	return result;
563}
564
565static	char	*last_search_pat;	/* last !?pat[?] search pattern */
566static	char	*last_search_match;	/* last !?pat[?] that matched */
567
568const char *
569get_history_event(const char *cmd, int *cindex, int qchar)
570{
571	int idx, sign, sub, num, begin, ret;
572	size_t len;
573	char	*pat;
574	const char *rptr;
575	HistEvent ev;
576
577	idx = *cindex;
578	if (cmd[idx++] != history_expansion_char)
579		return NULL;
580
581	/* find out which event to take */
582	if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') {
583		if (history(h, &ev, H_FIRST) != 0)
584			return NULL;
585		*cindex = cmd[idx]? (idx + 1):idx;
586		return ev.str;
587	}
588	sign = 0;
589	if (cmd[idx] == '-') {
590		sign = 1;
591		idx++;
592	}
593
594	if ('0' <= cmd[idx] && cmd[idx] <= '9') {
595		HIST_ENTRY *he;
596
597		num = 0;
598		while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') {
599			num = num * 10 + cmd[idx] - '0';
600			idx++;
601		}
602		if (sign)
603			num = history_length - num + history_base;
604
605		if (!(he = history_get(num)))
606			return NULL;
607
608		*cindex = idx;
609		return he->line;
610	}
611	sub = 0;
612	if (cmd[idx] == '?') {
613		sub = 1;
614		idx++;
615	}
616	begin = idx;
617	while (cmd[idx]) {
618		if (cmd[idx] == '\n')
619			break;
620		if (sub && cmd[idx] == '?')
621			break;
622		if (!sub && (cmd[idx] == ':' || cmd[idx] == ' '
623		    || cmd[idx] == '\t' || cmd[idx] == qchar))
624			break;
625		idx++;
626	}
627	len = (size_t)idx - (size_t)begin;
628	if (sub && cmd[idx] == '?')
629		idx++;
630	if (sub && len == 0 && last_search_pat && *last_search_pat)
631		pat = last_search_pat;
632	else if (len == 0)
633		return NULL;
634	else {
635		if ((pat = el_calloc(len + 1, sizeof(*pat))) == NULL)
636			return NULL;
637		(void)strlcpy(pat, cmd + begin, len + 1);
638	}
639
640	if (history(h, &ev, H_CURR) != 0) {
641		if (pat != last_search_pat)
642			el_free(pat);
643		return NULL;
644	}
645	num = ev.num;
646
647	if (sub) {
648		if (pat != last_search_pat) {
649			el_free(last_search_pat);
650			last_search_pat = pat;
651		}
652		ret = history_search(pat, -1);
653	} else
654		ret = history_search_prefix(pat, -1);
655
656	if (ret == -1) {
657		/* restore to end of list on failed search */
658		history(h, &ev, H_FIRST);
659		(void)fprintf(rl_outstream, "%s: Event not found\n", pat);
660		if (pat != last_search_pat)
661			el_free(pat);
662		return NULL;
663	}
664
665	if (sub && len) {
666		el_free(last_search_match);
667		last_search_match = strdup(pat);
668	}
669
670	if (pat != last_search_pat)
671		el_free(pat);
672
673	if (history(h, &ev, H_CURR) != 0)
674		return NULL;
675	*cindex = idx;
676	rptr = ev.str;
677
678	/* roll back to original position */
679	(void)history(h, &ev, H_SET, num);
680
681	return rptr;
682}
683
684static int
685getfrom(const char **cmdp, char **fromp, const char *search, int delim)
686{
687	size_t size = 16;
688	size_t len = 0;
689	const char *cmd = *cmdp;
690	char *what = el_realloc(*fromp, size * sizeof(*what));
691	if (what == NULL){
692		el_free(*fromp);
693		*fromp = NULL;
694		return 0;
695	}
696	for (; *cmd && *cmd != delim; cmd++) {
697		if (*cmd == '\\' && cmd[1] == delim)
698			cmd++;
699		if (len - 1 >= size) {
700			char *nwhat;
701			nwhat = el_realloc(what, (size <<= 1) * sizeof(*nwhat));
702			if (nwhat == NULL) {
703				el_free(what);
704				el_free(*fromp);
705				*cmdp = cmd;
706				*fromp = NULL;
707				return 0;
708			}
709			what = nwhat;
710		}
711		what[len++] = *cmd;
712	}
713	what[len] = '\0';
714	*fromp = what;
715	*cmdp = cmd;
716	if (*what == '\0') {
717		el_free(what);
718		if (search) {
719			*fromp = strdup(search);
720			if (*fromp == NULL) {
721				return 0;
722			}
723		} else {
724			*fromp = NULL;
725			return -1;
726		}
727	}
728	if (!*cmd) {
729		el_free(what);
730		*fromp = NULL;
731		return -1;
732	}
733
734	cmd++;	/* shift after delim */
735	*cmdp = cmd;
736
737	if (!*cmd) {
738		el_free(what);
739		*fromp = NULL;
740		return -1;
741	}
742	return 1;
743}
744
745static int
746getto(const char **cmdp, char **top, const char *from, int delim)
747{
748	size_t size = 16;
749	size_t len = 0;
750	size_t from_len = strlen(from);
751	const char *cmd = *cmdp;
752	char *with = el_realloc(*top, size * sizeof(*with));
753	*top = NULL;
754	if (with == NULL)
755		goto out;
756
757	for (; *cmd && *cmd != delim; cmd++) {
758		if (len + from_len + 1 >= size) {
759			char *nwith;
760			size += from_len + 1;
761			nwith = el_realloc(with, size * sizeof(*nwith));
762			if (nwith == NULL)
763				goto out;
764			with = nwith;
765		}
766		if (*cmd == '&') {
767			/* safe */
768			strcpy(&with[len], from);
769			len += from_len;
770			continue;
771		}
772		if (*cmd == '\\' && (*(cmd + 1) == delim || *(cmd + 1) == '&'))
773			cmd++;
774		with[len++] = *cmd;
775	}
776	if (!*cmd)
777		goto out;
778	with[len] = '\0';
779	*top = with;
780	*cmdp = cmd;
781	return 1;
782out:
783	el_free(with);
784	el_free(*top);
785	*top = NULL;
786	*cmdp = cmd;
787	return -1;
788}
789
790static void
791replace(char **tmp, int c)
792{
793	char *aptr;
794	if ((aptr = strrchr(*tmp, c)) == NULL)
795		return;
796	aptr = strdup(aptr + 1); // XXX: check
797	el_free(*tmp);
798	*tmp = aptr;
799}
800
801/*
802 * the real function doing history expansion - takes as argument command
803 * to do and data upon which the command should be executed
804 * does expansion the way I've understood readline documentation
805 *
806 * returns 0 if data was not modified, 1 if it was and 2 if the string
807 * should be only printed and not executed; in case of error,
808 * returns -1 and *result points to NULL
809 * it's the caller's responsibility to free() the string returned in *result
810 */
811static int
812_history_expand_command(const char *command, size_t offs, size_t cmdlen,
813    char **result)
814{
815	char *tmp, *search = NULL, *aptr, delim;
816	const char *ptr, *cmd;
817	static char *from = NULL, *to = NULL;
818	int start, end, idx, has_mods = 0;
819	int p_on = 0, g_on = 0, ev;
820
821	*result = NULL;
822	aptr = NULL;
823	ptr = NULL;
824
825	/* First get event specifier */
826	idx = 0;
827
828	if (strchr(":^*$", command[offs + 1])) {
829		char str[4];
830		/*
831		* "!:" is shorthand for "!!:".
832		* "!^", "!*" and "!$" are shorthand for
833		* "!!:^", "!!:*" and "!!:$" respectively.
834		*/
835		str[0] = str[1] = '!';
836		str[2] = '0';
837		ptr = get_history_event(str, &idx, 0);
838		idx = (command[offs + 1] == ':')? 1:0;
839		has_mods = 1;
840	} else {
841		if (command[offs + 1] == '#') {
842			/* use command so far */
843			if ((aptr = el_calloc(offs + 1, sizeof(*aptr)))
844			    == NULL)
845				return -1;
846			(void)strlcpy(aptr, command, offs + 1);
847			idx = 1;
848		} else {
849			int	qchar;
850
851			qchar = (offs > 0 && command[offs - 1] == '"')
852			    ? '"' : '\0';
853			ptr = get_history_event(command + offs, &idx, qchar);
854		}
855		has_mods = command[offs + (size_t)idx] == ':';
856	}
857
858	if (ptr == NULL && aptr == NULL)
859		return -1;
860
861	if (!has_mods) {
862		*result = strdup(aptr ? aptr : ptr);
863		if (aptr)
864			el_free(aptr);
865		if (*result == NULL)
866			return -1;
867		return 1;
868	}
869
870	cmd = command + offs + idx + 1;
871
872	/* Now parse any word designators */
873
874	if (*cmd == '%')	/* last word matched by ?pat? */
875		tmp = strdup(last_search_match ? last_search_match : "");
876	else if (strchr("^*$-0123456789", *cmd)) {
877		start = end = -1;
878		if (*cmd == '^')
879			start = end = 1, cmd++;
880		else if (*cmd == '$')
881			start = -1, cmd++;
882		else if (*cmd == '*')
883			start = 1, cmd++;
884		else if (*cmd == '-' || isdigit((unsigned char) *cmd)) {
885			start = 0;
886			while (*cmd && '0' <= *cmd && *cmd <= '9')
887				start = start * 10 + *cmd++ - '0';
888
889			if (*cmd == '-') {
890				if (isdigit((unsigned char) cmd[1])) {
891					cmd++;
892					end = 0;
893					while (*cmd && '0' <= *cmd && *cmd <= '9')
894						end = end * 10 + *cmd++ - '0';
895				} else if (cmd[1] == '$') {
896					cmd += 2;
897					end = -1;
898				} else {
899					cmd++;
900					end = -2;
901				}
902			} else if (*cmd == '*')
903				end = -1, cmd++;
904			else
905				end = start;
906		}
907		tmp = history_arg_extract(start, end, aptr? aptr:ptr);
908		if (tmp == NULL) {
909			(void)fprintf(rl_outstream, "%s: Bad word specifier",
910			    command + offs + idx);
911			if (aptr)
912				el_free(aptr);
913			return -1;
914		}
915	} else
916		tmp = strdup(aptr? aptr:ptr);
917
918	if (aptr)
919		el_free(aptr);
920
921	if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) {
922		*result = tmp;
923		return 1;
924	}
925
926	for (; *cmd; cmd++) {
927		switch (*cmd) {
928		case ':':
929			continue;
930		case 'h':	/* remove trailing path */
931			if ((aptr = strrchr(tmp, '/')) != NULL)
932				*aptr = '\0';
933			continue;
934		case 't':	/* remove leading path */
935			replace(&tmp, '/');
936			continue;
937		case 'r':	/* remove trailing suffix */
938			if ((aptr = strrchr(tmp, '.')) != NULL)
939				*aptr = '\0';
940			continue;
941		case 'e':	/* remove all but suffix */
942			replace(&tmp, '.');
943			continue;
944		case 'p':	/* print only */
945			p_on = 1;
946			continue;
947		case 'g':
948			g_on = 2;
949			continue;
950		case '&':
951			if (from == NULL || to == NULL)
952				continue;
953			/*FALLTHROUGH*/
954		case 's':
955			ev = -1;
956			delim = *++cmd;
957			if (delim == '\0' || *++cmd == '\0')
958				goto out;
959			if ((ev = getfrom(&cmd, &from, search, delim)) != 1)
960				goto out;
961			if ((ev = getto(&cmd, &to, from, delim)) != 1)
962				goto out;
963			aptr = _rl_compat_sub(tmp, from, to, g_on);
964			if (aptr) {
965				el_free(tmp);
966				tmp = aptr;
967			}
968			g_on = 0;
969			cmd--;
970			continue;
971		}
972	}
973	*result = tmp;
974	return p_on ? 2 : 1;
975out:
976	el_free(tmp);
977	return ev;
978
979}
980
981
982/*
983 * csh-style history expansion
984 */
985int
986history_expand(char *str, char **output)
987{
988	int ret = 0;
989	size_t idx, i, size;
990	char *tmp, *result;
991
992	if (h == NULL || e == NULL)
993		rl_initialize();
994
995	if (history_expansion_char == 0) {
996		*output = strdup(str);
997		return 0;
998	}
999
1000	*output = NULL;
1001	if (str[0] == history_subst_char) {
1002		/* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
1003		*output = el_calloc(strlen(str) + 4 + 1, sizeof(**output));
1004		if (*output == NULL)
1005			return 0;
1006		(*output)[0] = (*output)[1] = history_expansion_char;
1007		(*output)[2] = ':';
1008		(*output)[3] = 's';
1009		(void)strcpy((*output) + 4, str);
1010		str = *output;
1011	} else {
1012		*output = strdup(str);
1013		if (*output == NULL)
1014			return 0;
1015	}
1016
1017#define ADD_STRING(what, len, fr)					\
1018	{								\
1019		if (idx + len + 1 > size) {				\
1020			char *nresult = el_realloc(result,		\
1021			    (size += len + 1) * sizeof(*nresult));	\
1022			if (nresult == NULL) {				\
1023				el_free(*output);			\
1024				el_free(fr);				\
1025				return 0;				\
1026			}						\
1027			result = nresult;				\
1028		}							\
1029		(void)strlcpy(&result[idx], what, len + 1);		\
1030		idx += len;						\
1031	}
1032
1033	result = NULL;
1034	size = idx = 0;
1035	tmp = NULL;
1036	for (i = 0; str[i];) {
1037		int qchar, loop_again;
1038		size_t len, start, j;
1039
1040		qchar = 0;
1041		loop_again = 1;
1042		start = j = i;
1043loop:
1044		for (; str[j]; j++) {
1045			if (str[j] == '\\' &&
1046			    str[j + 1] == history_expansion_char) {
1047				len = strlen(&str[j + 1]) + 1;
1048				memmove(&str[j], &str[j + 1], len);
1049				continue;
1050			}
1051			if (!loop_again) {
1052				if (isspace((unsigned char) str[j])
1053				    || str[j] == qchar)
1054					break;
1055			}
1056			if (str[j] == history_expansion_char
1057			    && !strchr(history_no_expand_chars, str[j + 1])
1058			    && (!history_inhibit_expansion_function ||
1059			    (*history_inhibit_expansion_function)(str,
1060			    (int)j) == 0))
1061				break;
1062		}
1063
1064		if (str[j] && loop_again) {
1065			i = j;
1066			qchar = (j > 0 && str[j - 1] == '"' )? '"':0;
1067			j++;
1068			if (str[j] == history_expansion_char)
1069				j++;
1070			loop_again = 0;
1071			goto loop;
1072		}
1073		len = i - start;
1074		ADD_STRING(&str[start], len, NULL);
1075
1076		if (str[i] == '\0' || str[i] != history_expansion_char) {
1077			len = j - i;
1078			ADD_STRING(&str[i], len, NULL);
1079			if (start == 0)
1080				ret = 0;
1081			else
1082				ret = 1;
1083			break;
1084		}
1085		ret = _history_expand_command (str, i, (j - i), &tmp);
1086		if (ret > 0 && tmp) {
1087			len = strlen(tmp);
1088			ADD_STRING(tmp, len, tmp);
1089		}
1090		if (tmp) {
1091			el_free(tmp);
1092			tmp = NULL;
1093		}
1094		i = j;
1095	}
1096
1097	/* ret is 2 for "print only" option */
1098	if (ret == 2) {
1099		add_history(result);
1100#ifdef GDB_411_HACK
1101		/* gdb 4.11 has been shipped with readline, where */
1102		/* history_expand() returned -1 when the line	  */
1103		/* should not be executed; in readline 2.1+	  */
1104		/* it should return 2 in such a case		  */
1105		ret = -1;
1106#endif
1107	}
1108	el_free(*output);
1109	*output = result;
1110
1111	return ret;
1112}
1113
1114/*
1115* Return a string consisting of arguments of "str" from "start" to "end".
1116*/
1117char *
1118history_arg_extract(int start, int end, const char *str)
1119{
1120	size_t  i, len, max;
1121	char	**arr, *result = NULL;
1122
1123	arr = history_tokenize(str);
1124	if (!arr)
1125		return NULL;
1126	if (arr && *arr == NULL)
1127		goto out;
1128
1129	for (max = 0; arr[max]; max++)
1130		continue;
1131	max--;
1132
1133	if (start == '$')
1134		start = (int)max;
1135	if (end == '$')
1136		end = (int)max;
1137	if (end < 0)
1138		end = (int)max + end + 1;
1139	if (start < 0)
1140		start = end;
1141
1142	if (start < 0 || end < 0 || (size_t)start > max ||
1143	    (size_t)end > max || start > end)
1144		goto out;
1145
1146	for (i = (size_t)start, len = 0; i <= (size_t)end; i++)
1147		len += strlen(arr[i]) + 1;
1148	len++;
1149	result = el_calloc(len, sizeof(*result));
1150	if (result == NULL)
1151		goto out;
1152
1153	for (i = (size_t)start, len = 0; i <= (size_t)end; i++) {
1154		(void)strcpy(result + len, arr[i]);
1155		len += strlen(arr[i]);
1156		if (i < (size_t)end)
1157			result[len++] = ' ';
1158	}
1159	result[len] = '\0';
1160
1161out:
1162	for (i = 0; arr[i]; i++)
1163		el_free(arr[i]);
1164	el_free(arr);
1165
1166	return result;
1167}
1168
1169/*
1170 * Parse the string into individual tokens,
1171 * similar to how shell would do it.
1172 */
1173char **
1174history_tokenize(const char *str)
1175{
1176	int size = 1, idx = 0, i, start;
1177	size_t len;
1178	char **result = NULL, *temp, delim = '\0';
1179
1180	for (i = 0; str[i];) {
1181		while (isspace((unsigned char) str[i]))
1182			i++;
1183		start = i;
1184		for (; str[i];) {
1185			if (str[i] == '\\') {
1186				if (str[i+1] != '\0')
1187					i++;
1188			} else if (str[i] == delim)
1189				delim = '\0';
1190			else if (!delim &&
1191				    (isspace((unsigned char) str[i]) ||
1192				strchr("()<>;&|$", str[i])))
1193				break;
1194			else if (!delim && strchr("'`\"", str[i]))
1195				delim = str[i];
1196			if (str[i])
1197				i++;
1198		}
1199
1200		if (idx + 2 >= size) {
1201			char **nresult;
1202			size <<= 1;
1203			nresult = el_realloc(result, (size_t)size * sizeof(*nresult));
1204			if (nresult == NULL) {
1205				el_free(result);
1206				return NULL;
1207			}
1208			result = nresult;
1209		}
1210		len = (size_t)i - (size_t)start;
1211		temp = el_calloc(len + 1, sizeof(*temp));
1212		if (temp == NULL) {
1213			for (i = 0; i < idx; i++)
1214				el_free(result[i]);
1215			el_free(result);
1216			return NULL;
1217		}
1218		(void)strlcpy(temp, &str[start], len + 1);
1219		result[idx++] = temp;
1220		result[idx] = NULL;
1221		if (str[i])
1222			i++;
1223	}
1224	return result;
1225}
1226
1227
1228/*
1229 * limit size of history record to ``max'' events
1230 */
1231void
1232stifle_history(int max)
1233{
1234	HistEvent ev;
1235	HIST_ENTRY *he;
1236
1237	if (h == NULL || e == NULL)
1238		rl_initialize();
1239
1240	if (history(h, &ev, H_SETSIZE, max) == 0) {
1241		max_input_history = max;
1242		if (history_length > max)
1243			history_base = history_length - max;
1244		while (history_length > max) {
1245			he = remove_history(0);
1246			el_free(he->data);
1247			el_free((void *)(unsigned long)he->line);
1248			el_free(he);
1249		}
1250	}
1251}
1252
1253
1254/*
1255 * "unlimit" size of history - set the limit to maximum allowed int value
1256 */
1257int
1258unstifle_history(void)
1259{
1260	HistEvent ev;
1261	int omax;
1262
1263	history(h, &ev, H_SETSIZE, INT_MAX);
1264	omax = max_input_history;
1265	max_input_history = INT_MAX;
1266	return omax;		/* some value _must_ be returned */
1267}
1268
1269
1270int
1271history_is_stifled(void)
1272{
1273
1274	/* cannot return true answer */
1275	return max_input_history != INT_MAX;
1276}
1277
1278static const char _history_tmp_template[] = "/tmp/.historyXXXXXX";
1279
1280int
1281history_truncate_file (const char *filename, int nlines)
1282{
1283	int ret = 0;
1284	FILE *fp, *tp;
1285	char template[sizeof(_history_tmp_template)];
1286	char buf[4096];
1287	int fd;
1288	char *cp;
1289	off_t off;
1290	int count = 0;
1291	ssize_t left = 0;
1292
1293	if (filename == NULL && (filename = _default_history_file()) == NULL)
1294		return errno;
1295	if ((fp = fopen(filename, "r+")) == NULL)
1296		return errno;
1297	strcpy(template, _history_tmp_template);
1298	if ((fd = mkstemp(template)) == -1) {
1299		ret = errno;
1300		goto out1;
1301	}
1302
1303	if ((tp = fdopen(fd, "r+")) == NULL) {
1304		close(fd);
1305		ret = errno;
1306		goto out2;
1307	}
1308
1309	for(;;) {
1310		if (fread(buf, sizeof(buf), (size_t)1, fp) != 1) {
1311			if (ferror(fp)) {
1312				ret = errno;
1313				break;
1314			}
1315			if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) ==
1316			    (off_t)-1) {
1317				ret = errno;
1318				break;
1319			}
1320			left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), fp);
1321			if (ferror(fp)) {
1322				ret = errno;
1323				break;
1324			}
1325			if (left == 0) {
1326				count--;
1327				left = sizeof(buf);
1328			} else if (fwrite(buf, (size_t)left, (size_t)1, tp)
1329			    != 1) {
1330				ret = errno;
1331				break;
1332			}
1333			fflush(tp);
1334			break;
1335		}
1336		if (fwrite(buf, sizeof(buf), (size_t)1, tp) != 1) {
1337			ret = errno;
1338			break;
1339		}
1340		count++;
1341	}
1342	if (ret)
1343		goto out3;
1344	cp = buf + left - 1;
1345	if(*cp != '\n')
1346		cp++;
1347	for(;;) {
1348		while (--cp >= buf) {
1349			if (*cp == '\n') {
1350				if (--nlines == 0) {
1351					if (++cp >= buf + sizeof(buf)) {
1352						count++;
1353						cp = buf;
1354					}
1355					break;
1356				}
1357			}
1358		}
1359		if (nlines <= 0 || count == 0)
1360			break;
1361		count--;
1362		if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) {
1363			ret = errno;
1364			break;
1365		}
1366		if (fread(buf, sizeof(buf), (size_t)1, tp) != 1) {
1367			if (ferror(tp)) {
1368				ret = errno;
1369				break;
1370			}
1371			ret = EAGAIN;
1372			break;
1373		}
1374		cp = buf + sizeof(buf);
1375	}
1376
1377	if (ret || nlines > 0)
1378		goto out3;
1379
1380	if (fseeko(fp, (off_t)0, SEEK_SET) == (off_t)-1) {
1381		ret = errno;
1382		goto out3;
1383	}
1384
1385	if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) ==
1386	    (off_t)-1) {
1387		ret = errno;
1388		goto out3;
1389	}
1390
1391	for(;;) {
1392		if ((left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), tp)) == 0) {
1393			if (ferror(fp))
1394				ret = errno;
1395			break;
1396		}
1397		if (fwrite(buf, (size_t)left, (size_t)1, fp) != 1) {
1398			ret = errno;
1399			break;
1400		}
1401	}
1402	fflush(fp);
1403	if((off = ftello(fp)) > 0)
1404		(void)ftruncate(fileno(fp), off);
1405out3:
1406	fclose(tp);
1407out2:
1408	unlink(template);
1409out1:
1410	fclose(fp);
1411
1412	return ret;
1413}
1414
1415
1416/*
1417 * read history from a file given
1418 */
1419int
1420read_history(const char *filename)
1421{
1422	HistEvent ev;
1423
1424	if (h == NULL || e == NULL)
1425		rl_initialize();
1426	if (filename == NULL && (filename = _default_history_file()) == NULL)
1427		return errno;
1428	errno = 0;
1429	if (history(h, &ev, H_LOAD, filename) == -1)
1430		return errno ? errno : EINVAL;
1431	if (history(h, &ev, H_GETSIZE) == 0)
1432		history_length = ev.num;
1433	if (history_length < 0)
1434		return EINVAL;
1435	return 0;
1436}
1437
1438
1439/*
1440 * write history to a file given
1441 */
1442int
1443write_history(const char *filename)
1444{
1445	HistEvent ev;
1446
1447	if (h == NULL || e == NULL)
1448		rl_initialize();
1449	if (filename == NULL && (filename = _default_history_file()) == NULL)
1450		return errno;
1451	return history(h, &ev, H_SAVE, filename) == -1 ?
1452	    (errno ? errno : EINVAL) : 0;
1453}
1454
1455int
1456append_history(int n, const char *filename)
1457{
1458	HistEvent ev;
1459	FILE *fp;
1460
1461	if (h == NULL || e == NULL)
1462		rl_initialize();
1463	if (filename == NULL && (filename = _default_history_file()) == NULL)
1464		return errno;
1465
1466	if ((fp = fopen(filename, "a")) == NULL)
1467		return errno;
1468
1469	if (history(h, &ev, H_NSAVE_FP, (size_t)n,  fp) == -1) {
1470		int serrno = errno ? errno : EINVAL;
1471		fclose(fp);
1472		return serrno;
1473	}
1474	fclose(fp);
1475	return 0;
1476}
1477
1478/*
1479 * returns history ``num''th event
1480 *
1481 * returned pointer points to static variable
1482 */
1483HIST_ENTRY *
1484history_get(int num)
1485{
1486	static HIST_ENTRY she;
1487	HistEvent ev;
1488	int curr_num;
1489
1490	if (h == NULL || e == NULL)
1491		rl_initialize();
1492
1493	if (num < history_base)
1494		return NULL;
1495
1496	/* save current position */
1497	if (history(h, &ev, H_CURR) != 0)
1498		return NULL;
1499	curr_num = ev.num;
1500
1501	/*
1502	 * use H_DELDATA to set to nth history (without delete) by passing
1503	 * (void **)-1  -- as in history_set_pos
1504	 */
1505	if (history(h, &ev, H_DELDATA, num - history_base, (void **)-1) != 0)
1506		goto out;
1507
1508	/* get current entry */
1509	if (history(h, &ev, H_CURR) != 0)
1510		goto out;
1511	if (history(h, &ev, H_NEXT_EVDATA, ev.num, &she.data) != 0)
1512		goto out;
1513	she.line = ev.str;
1514
1515	/* restore pointer to where it was */
1516	(void)history(h, &ev, H_SET, curr_num);
1517
1518	return &she;
1519
1520out:
1521	/* restore pointer to where it was */
1522	(void)history(h, &ev, H_SET, curr_num);
1523	return NULL;
1524}
1525
1526
1527/*
1528 * add the line to history table
1529 */
1530int
1531add_history(const char *line)
1532{
1533	HistEvent ev;
1534
1535	if (h == NULL || e == NULL)
1536		rl_initialize();
1537
1538	if (history(h, &ev, H_ENTER, line) == -1)
1539		return 0;
1540
1541	(void)history(h, &ev, H_GETSIZE);
1542	if (ev.num == history_length)
1543		history_base++;
1544	else {
1545		history_offset++;
1546		history_length = ev.num;
1547	}
1548	return 0;
1549}
1550
1551
1552/*
1553 * remove the specified entry from the history list and return it.
1554 */
1555HIST_ENTRY *
1556remove_history(int num)
1557{
1558	HIST_ENTRY *he;
1559	HistEvent ev;
1560
1561	if (h == NULL || e == NULL)
1562		rl_initialize();
1563
1564	if ((he = el_malloc(sizeof(*he))) == NULL)
1565		return NULL;
1566
1567	if (history(h, &ev, H_DELDATA, num, &he->data) != 0) {
1568		el_free(he);
1569		return NULL;
1570	}
1571
1572	he->line = ev.str;
1573	if (history(h, &ev, H_GETSIZE) == 0)
1574		history_length = ev.num;
1575
1576	return he;
1577}
1578
1579
1580/*
1581 * replace the line and data of the num-th entry
1582 */
1583HIST_ENTRY *
1584replace_history_entry(int num, const char *line, histdata_t data)
1585{
1586	HIST_ENTRY *he;
1587	HistEvent ev;
1588	int curr_num;
1589
1590	if (h == NULL || e == NULL)
1591		rl_initialize();
1592
1593	/* save current position */
1594	if (history(h, &ev, H_CURR) != 0)
1595		return NULL;
1596	curr_num = ev.num;
1597
1598	/* start from the oldest */
1599	if (history(h, &ev, H_LAST) != 0)
1600		return NULL;	/* error */
1601
1602	if ((he = el_malloc(sizeof(*he))) == NULL)
1603		return NULL;
1604
1605	/* look forwards for event matching specified offset */
1606	if (history(h, &ev, H_NEXT_EVDATA, num, &he->data))
1607		goto out;
1608
1609	he->line = ev.str;
1610	if (he->line == NULL)
1611		goto out;
1612
1613	if (history(h, &ev, H_REPLACE, line, data))
1614		goto out;
1615
1616	/* restore pointer to where it was */
1617	if (history(h, &ev, H_SET, curr_num))
1618		goto out;
1619
1620	return he;
1621out:
1622	el_free(he);
1623	return NULL;
1624}
1625
1626/*
1627 * clear the history list - delete all entries
1628 */
1629void
1630clear_history(void)
1631{
1632	HistEvent ev;
1633
1634	if (h == NULL || e == NULL)
1635		rl_initialize();
1636
1637	(void)history(h, &ev, H_CLEAR);
1638	history_offset = history_length = 0;
1639}
1640
1641
1642/*
1643 * returns offset of the current history event
1644 */
1645int
1646where_history(void)
1647{
1648	return history_offset;
1649}
1650
1651static HIST_ENTRY **_history_listp;
1652static HIST_ENTRY *_history_list;
1653
1654HIST_ENTRY **
1655history_list(void)
1656{
1657	HistEvent ev;
1658	HIST_ENTRY **nlp, *nl;
1659	int i;
1660
1661	if (history(h, &ev, H_LAST) != 0)
1662		return NULL;
1663
1664	if ((nlp = el_realloc(_history_listp,
1665	    ((size_t)history_length + 1) * sizeof(*nlp))) == NULL)
1666		return NULL;
1667	_history_listp = nlp;
1668
1669	if ((nl = el_realloc(_history_list,
1670	    (size_t)history_length * sizeof(*nl))) == NULL)
1671		return NULL;
1672	_history_list = nl;
1673
1674	i = 0;
1675	do {
1676		_history_listp[i] = &_history_list[i];
1677		_history_list[i].line = ev.str;
1678		_history_list[i].data = NULL;
1679		if (i++ == history_length)
1680			abort();
1681	} while (history(h, &ev, H_PREV) == 0);
1682	_history_listp[i] = NULL;
1683	return _history_listp;
1684}
1685
1686/*
1687 * returns current history event or NULL if there is no such event
1688 */
1689HIST_ENTRY *
1690current_history(void)
1691{
1692	HistEvent ev;
1693
1694	if (history(h, &ev, H_PREV_EVENT, history_offset + 1) != 0)
1695		return NULL;
1696
1697	rl_he.line = ev.str;
1698	rl_he.data = NULL;
1699	return &rl_he;
1700}
1701
1702
1703/*
1704 * returns total number of bytes history events' data are using
1705 */
1706int
1707history_total_bytes(void)
1708{
1709	HistEvent ev;
1710	int curr_num;
1711	size_t size;
1712
1713	if (history(h, &ev, H_CURR) != 0)
1714		return -1;
1715	curr_num = ev.num;
1716
1717	(void)history(h, &ev, H_FIRST);
1718	size = 0;
1719	do
1720		size += strlen(ev.str) * sizeof(*ev.str);
1721	while (history(h, &ev, H_NEXT) == 0);
1722
1723	/* get to the same position as before */
1724	history(h, &ev, H_PREV_EVENT, curr_num);
1725
1726	return (int)size;
1727}
1728
1729
1730/*
1731 * sets the position in the history list to ``pos''
1732 */
1733int
1734history_set_pos(int pos)
1735{
1736	if (pos >= history_length || pos < 0)
1737		return 0;
1738
1739	history_offset = pos;
1740	return 1;
1741}
1742
1743
1744/*
1745 * returns previous event in history and shifts pointer accordingly
1746 * Note that readline and editline define directions in opposite ways.
1747 */
1748HIST_ENTRY *
1749previous_history(void)
1750{
1751	HistEvent ev;
1752
1753	if (history_offset == 0)
1754		return NULL;
1755
1756	if (history(h, &ev, H_LAST) != 0)
1757		return NULL;
1758
1759	history_offset--;
1760	return current_history();
1761}
1762
1763
1764/*
1765 * returns next event in history and shifts pointer accordingly
1766 */
1767HIST_ENTRY *
1768next_history(void)
1769{
1770	HistEvent ev;
1771
1772	if (history_offset >= history_length)
1773		return NULL;
1774
1775	if (history(h, &ev, H_LAST) != 0)
1776		return NULL;
1777
1778	history_offset++;
1779	return current_history();
1780}
1781
1782
1783/*
1784 * searches for first history event containing the str
1785 */
1786int
1787history_search(const char *str, int direction)
1788{
1789	HistEvent ev;
1790	const char *strp;
1791	int curr_num;
1792
1793	if (history(h, &ev, H_CURR) != 0)
1794		return -1;
1795	curr_num = ev.num;
1796
1797	for (;;) {
1798		if ((strp = strstr(ev.str, str)) != NULL)
1799			return (int)(strp - ev.str);
1800		if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0)
1801			break;
1802	}
1803	(void)history(h, &ev, H_SET, curr_num);
1804	return -1;
1805}
1806
1807
1808/*
1809 * searches for first history event beginning with str
1810 */
1811int
1812history_search_prefix(const char *str, int direction)
1813{
1814	HistEvent ev;
1815
1816	return (history(h, &ev, direction < 0 ?
1817	    H_PREV_STR : H_NEXT_STR, str));
1818}
1819
1820
1821/*
1822 * search for event in history containing str, starting at offset
1823 * abs(pos); continue backward, if pos<0, forward otherwise
1824 */
1825/* ARGSUSED */
1826int
1827history_search_pos(const char *str,
1828		   int direction __attribute__((__unused__)), int pos)
1829{
1830	HistEvent ev;
1831	int curr_num, off;
1832
1833	off = (pos > 0) ? pos : -pos;
1834	pos = (pos > 0) ? 1 : -1;
1835
1836	if (history(h, &ev, H_CURR) != 0)
1837		return -1;
1838	curr_num = ev.num;
1839
1840	if (!history_set_pos(off) || history(h, &ev, H_CURR) != 0)
1841		return -1;
1842
1843	for (;;) {
1844		if (strstr(ev.str, str))
1845			return off;
1846		if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0)
1847			break;
1848	}
1849
1850	/* set "current" pointer back to previous state */
1851	(void)history(h, &ev,
1852	    pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
1853
1854	return -1;
1855}
1856
1857
1858/********************************/
1859/* completion functions */
1860
1861char *
1862tilde_expand(char *name)
1863{
1864	return fn_tilde_expand(name);
1865}
1866
1867char *
1868filename_completion_function(const char *name, int state)
1869{
1870	return fn_filename_completion_function(name, state);
1871}
1872
1873/*
1874 * a completion generator for usernames; returns _first_ username
1875 * which starts with supplied text
1876 * text contains a partial username preceded by random character
1877 * (usually '~'); state resets search from start (??? should we do that anyway)
1878 * it's the caller's responsibility to free the returned value
1879 */
1880char *
1881username_completion_function(const char *text, int state)
1882{
1883#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT)
1884	struct passwd pwres;
1885	char pwbuf[1024];
1886#endif
1887	struct passwd *pass = NULL;
1888
1889	if (text[0] == '\0')
1890		return NULL;
1891
1892	if (*text == '~')
1893		text++;
1894
1895	if (state == 0)
1896		setpwent();
1897
1898	while (
1899#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT)
1900	    getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pass) == 0 && pass != NULL
1901#else
1902	    (pass = getpwent()) != NULL
1903#endif
1904	    && text[0] == pass->pw_name[0]
1905	    && strcmp(text, pass->pw_name) == 0)
1906		continue;
1907
1908	if (pass == NULL) {
1909		endpwent();
1910		return NULL;
1911	}
1912	return strdup(pass->pw_name);
1913}
1914
1915
1916/*
1917 * el-compatible wrapper to send TSTP on ^Z
1918 */
1919/* ARGSUSED */
1920static unsigned char
1921_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__)))
1922{
1923	(void)kill(0, SIGTSTP);
1924	return CC_NORM;
1925}
1926
1927static const char *
1928/*ARGSUSED*/
1929_rl_completion_append_character_function(const char *dummy
1930    __attribute__((__unused__)))
1931{
1932	static char buf[2];
1933	buf[0] = (char)rl_completion_append_character;
1934	buf[1] = '\0';
1935	return buf;
1936}
1937
1938
1939/*
1940 * Display list of strings in columnar format on readline's output stream.
1941 * 'matches' is list of strings, 'len' is number of strings in 'matches',
1942 * 'max' is maximum length of string in 'matches'.
1943 */
1944void
1945rl_display_match_list(char **matches, int len, int max)
1946{
1947
1948	fn_display_match_list(e, matches, (size_t)len, (size_t)max,
1949		_rl_completion_append_character_function);
1950}
1951
1952/*
1953 * complete word at current point
1954 */
1955/* ARGSUSED */
1956int
1957rl_complete(int ignore __attribute__((__unused__)), int invoking_key)
1958{
1959	static ct_buffer_t wbreak_conv, sprefix_conv;
1960	const char *breakchars;
1961
1962	if (h == NULL || e == NULL)
1963		rl_initialize();
1964
1965	if (rl_inhibit_completion) {
1966		char arr[2];
1967		arr[0] = (char)invoking_key;
1968		arr[1] = '\0';
1969		el_insertstr(e, arr);
1970		return CC_REFRESH;
1971	}
1972
1973	if (rl_completion_word_break_hook != NULL)
1974		breakchars = (*rl_completion_word_break_hook)();
1975	else
1976		breakchars = rl_basic_word_break_characters;
1977
1978	_rl_update_pos();
1979
1980	/* Just look at how many global variables modify this operation! */
1981	return fn_complete(e,
1982	    (rl_compentry_func_t *)rl_completion_entry_function,
1983	    rl_attempted_completion_function,
1984	    ct_decode_string(rl_basic_word_break_characters, &wbreak_conv),
1985	    ct_decode_string(breakchars, &sprefix_conv),
1986	    _rl_completion_append_character_function,
1987	    (size_t)rl_completion_query_items,
1988	    &rl_completion_type, &rl_attempted_completion_over,
1989	    &rl_point, &rl_end);
1990
1991
1992}
1993
1994
1995/* ARGSUSED */
1996static unsigned char
1997_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch)
1998{
1999	return (unsigned char)rl_complete(0, ch);
2000}
2001
2002/*
2003 * misc other functions
2004 */
2005
2006/*
2007 * bind key c to readline-type function func
2008 */
2009int
2010rl_bind_key(int c, rl_command_func_t *func)
2011{
2012	int retval = -1;
2013
2014	if (h == NULL || e == NULL)
2015		rl_initialize();
2016
2017	if (func == rl_insert) {
2018		/* XXX notice there is no range checking of ``c'' */
2019		e->el_map.key[c] = ED_INSERT;
2020		retval = 0;
2021	}
2022	return retval;
2023}
2024
2025
2026/*
2027 * read one key from input - handles chars pushed back
2028 * to input stream also
2029 */
2030int
2031rl_read_key(void)
2032{
2033	char fooarr[2 * sizeof(int)];
2034
2035	if (e == NULL || h == NULL)
2036		rl_initialize();
2037
2038	return el_getc(e, fooarr);
2039}
2040
2041
2042/*
2043 * reset the terminal
2044 */
2045/* ARGSUSED */
2046int
2047rl_reset_terminal(const char *p __attribute__((__unused__)))
2048{
2049
2050	if (h == NULL || e == NULL)
2051		rl_initialize();
2052	el_reset(e);
2053	return 0;
2054}
2055
2056
2057/*
2058 * insert character ``c'' back into input stream, ``count'' times
2059 */
2060int
2061rl_insert(int count, int c)
2062{
2063	char arr[2];
2064
2065	if (h == NULL || e == NULL)
2066		rl_initialize();
2067
2068	/* XXX - int -> char conversion can lose on multichars */
2069	arr[0] = (char)c;
2070	arr[1] = '\0';
2071
2072	for (; count > 0; count--)
2073		el_push(e, arr);
2074
2075	return 0;
2076}
2077
2078int
2079rl_insert_text(const char *text)
2080{
2081	if (!text || *text == 0)
2082		return 0;
2083
2084	if (h == NULL || e == NULL)
2085		rl_initialize();
2086
2087	if (el_insertstr(e, text) < 0)
2088		return 0;
2089	return (int)strlen(text);
2090}
2091
2092/*ARGSUSED*/
2093int
2094rl_newline(int count __attribute__((__unused__)),
2095    int c __attribute__((__unused__)))
2096{
2097	/*
2098	 * Readline-4.0 appears to ignore the args.
2099	 */
2100	return rl_insert(1, '\n');
2101}
2102
2103/*ARGSUSED*/
2104static unsigned char
2105rl_bind_wrapper(EditLine *el __attribute__((__unused__)), unsigned char c)
2106{
2107	if (map[c] == NULL)
2108		return CC_ERROR;
2109
2110	_rl_update_pos();
2111
2112	(*map[c])(1, c);
2113
2114	/* If rl_done was set by the above call, deal with it here */
2115	if (rl_done)
2116		return CC_EOF;
2117
2118	return CC_NORM;
2119}
2120
2121int
2122rl_add_defun(const char *name, rl_command_func_t *fun, int c)
2123{
2124	char dest[8];
2125	if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0)
2126		return -1;
2127	map[(unsigned char)c] = fun;
2128	el_set(e, EL_ADDFN, name, name, rl_bind_wrapper);
2129	vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0);
2130	el_set(e, EL_BIND, dest, name, NULL);
2131	return 0;
2132}
2133
2134void
2135rl_callback_read_char(void)
2136{
2137	int count = 0, done = 0;
2138	const char *buf = el_gets(e, &count);
2139	char *wbuf;
2140
2141	el_set(e, EL_UNBUFFERED, 1);
2142	if (buf == NULL || count-- <= 0)
2143		return;
2144	if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF])
2145		done = 1;
2146	if (buf[count] == '\n' || buf[count] == '\r')
2147		done = 2;
2148
2149	if (done && rl_linefunc != NULL) {
2150		el_set(e, EL_UNBUFFERED, 0);
2151		if (done == 2) {
2152			if ((wbuf = strdup(buf)) != NULL)
2153				wbuf[count] = '\0';
2154			RL_SETSTATE(RL_STATE_DONE);
2155		} else
2156			wbuf = NULL;
2157		(*(void (*)(const char *))rl_linefunc)(wbuf);
2158	}
2159	_rl_update_pos();
2160}
2161
2162void
2163rl_callback_handler_install(const char *prompt, rl_vcpfunc_t *linefunc)
2164{
2165	if (e == NULL) {
2166		rl_initialize();
2167	}
2168	(void)rl_set_prompt(prompt);
2169	rl_linefunc = linefunc;
2170	el_set(e, EL_UNBUFFERED, 1);
2171}
2172
2173void
2174rl_callback_handler_remove(void)
2175{
2176	el_set(e, EL_UNBUFFERED, 0);
2177	rl_linefunc = NULL;
2178}
2179
2180void
2181rl_redisplay(void)
2182{
2183	char a[2];
2184	a[0] = (char)e->el_tty.t_c[TS_IO][C_REPRINT];
2185	a[1] = '\0';
2186	el_push(e, a);
2187	rl_forced_update_display();
2188}
2189
2190int
2191rl_get_previous_history(int count, int key)
2192{
2193	char a[2];
2194	a[0] = (char)key;
2195	a[1] = '\0';
2196	while (count--)
2197		el_push(e, a);
2198	return 0;
2199}
2200
2201void
2202/*ARGSUSED*/
2203rl_prep_terminal(int meta_flag __attribute__((__unused__)))
2204{
2205	el_set(e, EL_PREP_TERM, 1);
2206}
2207
2208void
2209rl_deprep_terminal(void)
2210{
2211	el_set(e, EL_PREP_TERM, 0);
2212}
2213
2214int
2215rl_read_init_file(const char *s)
2216{
2217	return el_source(e, s);
2218}
2219
2220int
2221rl_parse_and_bind(const char *line)
2222{
2223	const char **argv;
2224	int argc;
2225	Tokenizer *tok;
2226
2227	tok = tok_init(NULL);
2228	tok_str(tok, line, &argc, &argv);
2229	argc = el_parse(e, argc, argv);
2230	tok_end(tok);
2231	return argc ? 1 : 0;
2232}
2233
2234int
2235rl_variable_bind(const char *var, const char *value)
2236{
2237	/*
2238	 * The proper return value is undocument, but this is what the
2239	 * readline source seems to do.
2240	 */
2241	return el_set(e, EL_BIND, "", var, value, NULL) == -1 ? 1 : 0;
2242}
2243
2244int
2245rl_stuff_char(int c)
2246{
2247	char buf[2];
2248
2249	buf[0] = (char)c;
2250	buf[1] = '\0';
2251	el_insertstr(e, buf);
2252	return 1;
2253}
2254
2255static int
2256_rl_event_read_char(EditLine *el, wchar_t *wc)
2257{
2258	char	ch;
2259	int	n;
2260	ssize_t num_read = 0;
2261
2262	ch = '\0';
2263	*wc = L'\0';
2264	while (rl_event_hook) {
2265
2266		(*rl_event_hook)();
2267
2268#if defined(FIONREAD)
2269		if (ioctl(el->el_infd, FIONREAD, &n) < 0)
2270			return -1;
2271		if (n)
2272			num_read = read(el->el_infd, &ch, (size_t)1);
2273		else
2274			num_read = 0;
2275#elif defined(F_SETFL) && defined(O_NDELAY)
2276		if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0)
2277			return -1;
2278		if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0)
2279			return -1;
2280		num_read = read(el->el_infd, &ch, 1);
2281		if (fcntl(el->el_infd, F_SETFL, n))
2282			return -1;
2283#else
2284		/* not non-blocking, but what you gonna do? */
2285		num_read = read(el->el_infd, &ch, 1);
2286		return -1;
2287#endif
2288
2289		if (num_read < 0 && errno == EAGAIN)
2290			continue;
2291		if (num_read == 0)
2292			continue;
2293		break;
2294	}
2295	if (!rl_event_hook)
2296		el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN);
2297	*wc = (wchar_t)ch;
2298	return (int)num_read;
2299}
2300
2301static void
2302_rl_update_pos(void)
2303{
2304	const LineInfo *li = el_line(e);
2305
2306	rl_point = (int)(li->cursor - li->buffer);
2307	rl_end = (int)(li->lastchar - li->buffer);
2308	rl_line_buffer[rl_end] = '\0';
2309}
2310
2311char *
2312rl_copy_text(int from, int to)
2313{
2314	const LineInfo *li;
2315	size_t len;
2316	char * out;
2317
2318	if (h == NULL || e == NULL)
2319		rl_initialize();
2320
2321	li = el_line(e);
2322
2323	if (from > to)
2324		return NULL;
2325
2326	if (li->buffer + from > li->lastchar)
2327		from = (int)(li->lastchar - li->buffer);
2328
2329	if (li->buffer + to > li->lastchar)
2330		to = (int)(li->lastchar - li->buffer);
2331
2332	len = (size_t)(to - from);
2333	out = el_malloc((size_t)len + 1);
2334	if (out == NULL)
2335		return NULL;
2336	(void)strlcpy(out, li->buffer + from , len);
2337
2338	return out;
2339}
2340
2341void
2342rl_replace_line(const char * text, int clear_undo __attribute__((__unused__)))
2343{
2344	if (!text || *text == 0)
2345		return;
2346
2347	if (h == NULL || e == NULL)
2348		rl_initialize();
2349
2350	el_replacestr(e, text);
2351}
2352
2353int
2354rl_delete_text(int start, int end)
2355{
2356
2357	if (h == NULL || e == NULL)
2358		rl_initialize();
2359
2360	return el_deletestr1(e, start, end);
2361}
2362
2363void
2364rl_get_screen_size(int *rows, int *cols)
2365{
2366	if (rows)
2367		el_get(e, EL_GETTC, "li", rows);
2368	if (cols)
2369		el_get(e, EL_GETTC, "co", cols);
2370}
2371
2372#define MAX_MESSAGE 160
2373void
2374rl_message(const char *format, ...)
2375{
2376	char msg[MAX_MESSAGE];
2377	va_list args;
2378
2379	va_start(args, format);
2380	vsnprintf(msg, sizeof(msg), format, args);
2381	va_end(args);
2382
2383	rl_set_prompt(msg);
2384	rl_forced_update_display();
2385}
2386
2387void
2388rl_set_screen_size(int rows, int cols)
2389{
2390	char buf[64];
2391	(void)snprintf(buf, sizeof(buf), "%d", rows);
2392	el_set(e, EL_SETTC, "li", buf, NULL);
2393	(void)snprintf(buf, sizeof(buf), "%d", cols);
2394	el_set(e, EL_SETTC, "co", buf, NULL);
2395}
2396
2397char **
2398rl_completion_matches(const char *str, rl_compentry_func_t *fun)
2399{
2400	size_t len, max, i, j, min;
2401	char **list, *match, *a, *b;
2402
2403	len = 1;
2404	max = 10;
2405	if ((list = el_calloc(max, sizeof(*list))) == NULL)
2406		return NULL;
2407
2408	while ((match = (*fun)(str, (int)(len - 1))) != NULL) {
2409		list[len++] = match;
2410		if (len == max) {
2411			char **nl;
2412			max += 10;
2413			if ((nl = el_realloc(list, max * sizeof(*nl))) == NULL)
2414				goto out;
2415			list = nl;
2416		}
2417	}
2418	if (len == 1)
2419		goto out;
2420	list[len] = NULL;
2421	if (len == 2) {
2422		if ((list[0] = strdup(list[1])) == NULL)
2423			goto out;
2424		return list;
2425	}
2426	qsort(&list[1], len - 1, sizeof(*list),
2427	    (int (*)(const void *, const void *)) strcmp);
2428	min = SIZE_MAX;
2429	for (i = 1, a = list[i]; i < len - 1; i++, a = b) {
2430		b = list[i + 1];
2431		for (j = 0; a[j] && a[j] == b[j]; j++)
2432			continue;
2433		if (min > j)
2434			min = j;
2435	}
2436	if (min == 0 && *str) {
2437		if ((list[0] = strdup(str)) == NULL)
2438			goto out;
2439	} else {
2440		if ((list[0] = el_calloc(min + 1, sizeof(*list[0]))) == NULL)
2441			goto out;
2442		(void)memcpy(list[0], list[1], min);
2443		list[0][min] = '\0';
2444	}
2445	return list;
2446
2447out:
2448	el_free(list);
2449	return NULL;
2450}
2451
2452char *
2453rl_filename_completion_function (const char *text, int state)
2454{
2455	return fn_filename_completion_function(text, state);
2456}
2457
2458void
2459rl_forced_update_display(void)
2460{
2461	el_set(e, EL_REFRESH);
2462}
2463
2464int
2465_rl_abort_internal(void)
2466{
2467	el_beep(e);
2468	longjmp(topbuf, 1);
2469	/*NOTREACHED*/
2470}
2471
2472int
2473_rl_qsort_string_compare(char **s1, char **s2)
2474{
2475	return strcoll(*s1, *s2);
2476}
2477
2478HISTORY_STATE *
2479history_get_history_state(void)
2480{
2481	HISTORY_STATE *hs;
2482
2483	if ((hs = el_malloc(sizeof(*hs))) == NULL)
2484		return NULL;
2485	hs->length = history_length;
2486	return hs;
2487}
2488
2489int
2490/*ARGSUSED*/
2491rl_kill_text(int from __attribute__((__unused__)),
2492    int to __attribute__((__unused__)))
2493{
2494	return 0;
2495}
2496
2497Keymap
2498rl_make_bare_keymap(void)
2499{
2500	return NULL;
2501}
2502
2503Keymap
2504rl_get_keymap(void)
2505{
2506	return NULL;
2507}
2508
2509void
2510/*ARGSUSED*/
2511rl_set_keymap(Keymap k __attribute__((__unused__)))
2512{
2513}
2514
2515int
2516/*ARGSUSED*/
2517rl_generic_bind(int type __attribute__((__unused__)),
2518    const char * keyseq __attribute__((__unused__)),
2519    const char * data __attribute__((__unused__)),
2520    Keymap k __attribute__((__unused__)))
2521{
2522	return 0;
2523}
2524
2525int
2526/*ARGSUSED*/
2527rl_bind_key_in_map(int key __attribute__((__unused__)),
2528    rl_command_func_t *fun __attribute__((__unused__)),
2529    Keymap k __attribute__((__unused__)))
2530{
2531	return 0;
2532}
2533
2534int
2535rl_set_key(const char *keyseq  __attribute__((__unused__)),
2536	rl_command_func_t *function __attribute__((__unused__)),
2537	Keymap k __attribute__((__unused__)))
2538{
2539	return 0;
2540}
2541
2542/* unsupported, but needed by python */
2543void
2544rl_cleanup_after_signal(void)
2545{
2546}
2547
2548int
2549rl_on_new_line(void)
2550{
2551	return 0;
2552}
2553
2554void
2555rl_free_line_state(void)
2556{
2557}
2558
2559int
2560/*ARGSUSED*/
2561rl_set_keyboard_input_timeout(int u __attribute__((__unused__)))
2562{
2563	return 0;
2564}
2565
2566void
2567rl_resize_terminal(void)
2568{
2569	el_resize(e);
2570}
2571
2572void
2573rl_reset_after_signal(void)
2574{
2575	if (rl_prep_term_function)
2576		(*rl_prep_term_function)();
2577}
2578
2579void
2580rl_echo_signal_char(int sig)
2581{
2582	int c = tty_get_signal_character(e, sig);
2583	if (c == -1)
2584		return;
2585	re_putc(e, c, 0);
2586}
2587
2588int
2589rl_crlf(void)
2590{
2591	re_putc(e, '\n', 0);
2592	return 0;
2593}
2594
2595int
2596rl_ding(void)
2597{
2598	re_putc(e, '\a', 0);
2599	return 0;
2600}
2601
2602int
2603rl_abort(int count, int key)
2604{
2605	return count && key ? 0 : 0;
2606}
2607
2608int
2609rl_set_keymap_name(const char *name, Keymap k)
2610{
2611	return name && k ? 0 : 0;
2612}
2613
2614histdata_t
2615free_history_entry(HIST_ENTRY *he)
2616{
2617	return he ? NULL : NULL;
2618}
2619
2620void
2621_rl_erase_entire_line(void)
2622{
2623}
2624