xref: /netbsd/lib/libedit/readline.c (revision 9138b925)
1*9138b925Schristos /*	$NetBSD: readline.c,v 1.181 2023/04/25 17:51:32 christos Exp $	*/
2f7de801dSchristos 
3f7de801dSchristos /*-
4f7de801dSchristos  * Copyright (c) 1997 The NetBSD Foundation, Inc.
5f7de801dSchristos  * All rights reserved.
6f7de801dSchristos  *
7f7de801dSchristos  * This code is derived from software contributed to The NetBSD Foundation
8f7de801dSchristos  * by Jaromir Dolecek.
9f7de801dSchristos  *
10f7de801dSchristos  * Redistribution and use in source and binary forms, with or without
11f7de801dSchristos  * modification, are permitted provided that the following conditions
12f7de801dSchristos  * are met:
13f7de801dSchristos  * 1. Redistributions of source code must retain the above copyright
14f7de801dSchristos  *    notice, this list of conditions and the following disclaimer.
15f7de801dSchristos  * 2. Redistributions in binary form must reproduce the above copyright
16f7de801dSchristos  *    notice, this list of conditions and the following disclaimer in the
17f7de801dSchristos  *    documentation and/or other materials provided with the distribution.
18f7de801dSchristos  *
19f7de801dSchristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20f7de801dSchristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21f7de801dSchristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22f7de801dSchristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23f7de801dSchristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24f7de801dSchristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25f7de801dSchristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26f7de801dSchristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27f7de801dSchristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28f7de801dSchristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29f7de801dSchristos  * POSSIBILITY OF SUCH DAMAGE.
30f7de801dSchristos  */
31f7de801dSchristos 
320e0ac6b7Schristos #include "config.h"
33f7de801dSchristos #if !defined(lint) && !defined(SCCSID)
34*9138b925Schristos __RCSID("$NetBSD: readline.c,v 1.181 2023/04/25 17:51:32 christos Exp $");
35f7de801dSchristos #endif /* not lint && not SCCSID */
36f7de801dSchristos 
37f7de801dSchristos #include <sys/types.h>
38f7de801dSchristos #include <sys/stat.h>
39f7de801dSchristos #include <ctype.h>
40e49871f3Schristos #include <dirent.h>
415d79eff8Schristos #include <errno.h>
425d79eff8Schristos #include <fcntl.h>
43e49871f3Schristos #include <limits.h>
44e49871f3Schristos #include <pwd.h>
456b8a7930Schristos #include <setjmp.h>
460b50653eSchristos #include <stdarg.h>
47e49871f3Schristos #include <stdint.h>
48e49871f3Schristos #include <stdio.h>
49e49871f3Schristos #include <stdlib.h>
50e49871f3Schristos #include <string.h>
51e49871f3Schristos #include <unistd.h>
52552716dcSchristos #include <vis.h>
534b7bc181Schristos 
54*9138b925Schristos #define completion_matches xxx_completion_matches
55fc16547fSsketch #include "readline/readline.h"
56*9138b925Schristos #undef completion_matches
57f7de801dSchristos #include "el.h"
581d061c21Schristos #include "fcns.h"
5941a59814Sdsl #include "filecomplete.h"
60f7de801dSchristos 
61213f1e24Schristos void rl_prep_terminal(int);
62213f1e24Schristos void rl_deprep_terminal(void);
63213f1e24Schristos 
64f7de801dSchristos /* for rl_complete() */
65f7de801dSchristos #define TAB		'\r'
66f7de801dSchristos 
67f7de801dSchristos /* see comment at the #ifdef for sense of this */
688b40dcaeSchristos /* #define GDB_411_HACK */
69f7de801dSchristos 
70f7de801dSchristos /* readline compatibility stuff - look at readline sources/documentation */
71f7de801dSchristos /* to see what these variables mean */
72f7de801dSchristos const char *rl_library_version = "EditLine wrapper";
73ea3813edSchristos int rl_readline_version = RL_READLINE_VERSION;
740e0ac6b7Schristos static char empty[] = { '\0' };
750e0ac6b7Schristos static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' };
760e0ac6b7Schristos static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$',
770e0ac6b7Schristos     '>', '<', '=', ';', '|', '&', '{', '(', '\0' };
7808dba207Schristos const char *rl_readline_name = empty;
79f7de801dSchristos FILE *rl_instream = NULL;
80f7de801dSchristos FILE *rl_outstream = NULL;
81f7de801dSchristos int rl_point = 0;
82f7de801dSchristos int rl_end = 0;
83f7de801dSchristos char *rl_line_buffer = NULL;
8449603ec5Schristos rl_vcpfunc_t *rl_linefunc = NULL;
855d79eff8Schristos int rl_done = 0;
8658d5a0ffSchristos rl_hook_func_t *rl_event_hook = NULL;
876b8a7930Schristos KEYMAP_ENTRY_ARRAY emacs_standard_keymap,
886b8a7930Schristos     emacs_meta_keymap,
896b8a7930Schristos     emacs_ctlx_keymap;
90bb717f4cSchristos /*
91bb717f4cSchristos  * The following is not implemented; we always catch signals in the
92bb717f4cSchristos  * libedit fashion: set handlers on entry to el_gets() and clear them
93bb717f4cSchristos  * on the way out. This simplistic approach works for most cases; if
94bb717f4cSchristos  * it does not work for your application, please let us know.
95bb717f4cSchristos  */
96bb717f4cSchristos int rl_catch_signals = 1;
97bb717f4cSchristos int rl_catch_sigwinch = 1;
98f7de801dSchristos 
99f7de801dSchristos int history_base = 1;		/* probably never subject to change */
100f7de801dSchristos int history_length = 0;
101357ec4e8Schristos int history_offset = 0;
102f7de801dSchristos int max_input_history = 0;
103f7de801dSchristos char history_expansion_char = '!';
104f7de801dSchristos char history_subst_char = '^';
1050e0ac6b7Schristos char *history_no_expand_chars = expand_chars;
106*9138b925Schristos rl_linebuf_func_t *history_inhibit_expansion_function = NULL;
1078b40dcaeSchristos char *history_arg_extract(int start, int end, const char *str);
108f7de801dSchristos 
109f7de801dSchristos int rl_inhibit_completion = 0;
110f7de801dSchristos int rl_attempted_completion_over = 0;
11108dba207Schristos const char *rl_basic_word_break_characters = break_chars;
112f7de801dSchristos char *rl_completer_word_break_characters = NULL;
113c7c7d2a8Schristos const char *rl_completer_quote_characters = NULL;
1140d6bfd89Schristos const char *rl_basic_quote_characters = "\"'";
11549603ec5Schristos rl_compentry_func_t *rl_completion_entry_function = NULL;
1169c8690d3Schristos char *(*rl_completion_word_break_hook)(void) = NULL;
11749603ec5Schristos rl_completion_func_t *rl_attempted_completion_function = NULL;
1186beb6f38Schristos rl_hook_func_t *rl_pre_input_hook = NULL;
1196beb6f38Schristos rl_hook_func_t *rl_startup1_hook = NULL;
1205f3802caSchristos int (*rl_getc_function)(FILE *) = NULL;
121166e18a7Schristos char *rl_terminal_name = NULL;
122166e18a7Schristos int rl_already_prompted = 0;
123166e18a7Schristos int rl_filename_completion_desired = 0;
124166e18a7Schristos int rl_ignore_completion_duplicates = 0;
1256b8a7930Schristos int readline_echoing_p = 1;
1266b8a7930Schristos int _rl_print_completions_horizontally = 0;
1279debc6b7Schristos rl_voidfunc_t *rl_redisplay_function = NULL;
1286beb6f38Schristos rl_hook_func_t *rl_startup_hook = NULL;
1299debc6b7Schristos rl_compdisp_func_t *rl_completion_display_matches_hook = NULL;
1309debc6b7Schristos rl_vintfunc_t *rl_prep_term_function = (rl_vintfunc_t *)rl_prep_terminal;
1319debc6b7Schristos rl_voidfunc_t *rl_deprep_term_function = (rl_voidfunc_t *)rl_deprep_terminal;
132ea3813edSchristos KEYMAP_ENTRY_ARRAY emacs_meta_keymap;
1332feacb00Schristos unsigned long rl_readline_state = RL_STATE_NONE;
1340d6bfd89Schristos int _rl_complete_mark_directories;
1350d6bfd89Schristos rl_icppfunc_t *rl_directory_completion_hook;
1360d6bfd89Schristos int rl_completion_suppress_append;
1370d6bfd89Schristos int rl_sort_completion_matches;
1380d6bfd89Schristos int _rl_completion_prefix_display_length;
1390d6bfd89Schristos int _rl_echoing_p;
1400d6bfd89Schristos int history_max_entries;
1410d6bfd89Schristos char *rl_display_prompt;
1420b50653eSchristos int rl_erase_empty_line;
143f7de801dSchristos 
1444acffb64Sjdolecek /*
145166e18a7Schristos  * The current prompt string.
146166e18a7Schristos  */
147166e18a7Schristos char *rl_prompt = NULL;
1480b50653eSchristos char *rl_prompt_saved = NULL;
149166e18a7Schristos /*
1504acffb64Sjdolecek  * This is set to character indicating type of completion being done by
1514acffb64Sjdolecek  * rl_complete_internal(); this is available for application completion
1524acffb64Sjdolecek  * functions.
1534acffb64Sjdolecek  */
1544acffb64Sjdolecek int rl_completion_type = 0;
1554acffb64Sjdolecek 
1564acffb64Sjdolecek /*
1574acffb64Sjdolecek  * If more than this number of items results from query for possible
1584acffb64Sjdolecek  * completions, we ask user if they are sure to really display the list.
1594acffb64Sjdolecek  */
1604acffb64Sjdolecek int rl_completion_query_items = 100;
1614acffb64Sjdolecek 
1624acffb64Sjdolecek /*
163a85f9ca2Sjdolecek  * List of characters which are word break characters, but should be left
164a85f9ca2Sjdolecek  * in the parsed text when it is passed to the completion function.
165a85f9ca2Sjdolecek  * Shell uses this to help determine what kind of completing to do.
1664acffb64Sjdolecek  */
16708dba207Schristos const char *rl_special_prefixes = NULL;
168a85f9ca2Sjdolecek 
169a85f9ca2Sjdolecek /*
170a85f9ca2Sjdolecek  * This is the character appended to the completed words if at the end of
171a85f9ca2Sjdolecek  * the line. Default is ' ' (a space).
172a85f9ca2Sjdolecek  */
173a85f9ca2Sjdolecek int rl_completion_append_character = ' ';
174a85f9ca2Sjdolecek 
175a85f9ca2Sjdolecek /* stuff below is used internally by libedit for readline emulation */
176a85f9ca2Sjdolecek 
177b3543150Schristos static History *h = NULL;
178f7de801dSchristos static EditLine *e = NULL;
179d64206caSchristos static rl_command_func_t *map[256];
1806b8a7930Schristos static jmp_buf topbuf;
181f7de801dSchristos 
182f7de801dSchristos /* internal functions */
183d30d584aSlukem static unsigned char	 _el_rl_complete(EditLine *, int);
184ac4e17d0Schristos static unsigned char	 _el_rl_tstp(EditLine *, int);
185d30d584aSlukem static char		*_get_prompt(EditLine *);
186a7b81d12Schristos static int		 _getc_function(EditLine *, wchar_t *);
1878b40dcaeSchristos static int		 _history_expand_command(const char *, size_t, size_t,
1888b40dcaeSchristos     char **);
189d30d584aSlukem static char		*_rl_compat_sub(const char *, const char *,
190d30d584aSlukem     const char *, int);
191a7b81d12Schristos static int		 _rl_event_read_char(EditLine *, wchar_t *);
192af62817eSchristos static void		 _rl_update_pos(void);
193f7de801dSchristos 
194357ec4e8Schristos static HIST_ENTRY rl_he;
195d30d584aSlukem 
196a0be074dSchristos /* ARGSUSED */
197f7de801dSchristos static char *
_get_prompt(EditLine * el)198839ca00bSchristos _get_prompt(EditLine *el __attribute__((__unused__)))
199f7de801dSchristos {
200166e18a7Schristos 	rl_already_prompted = 1;
20115a0bb6cSchristos 	return rl_prompt;
202f7de801dSchristos }
203f7de801dSchristos 
204d30d584aSlukem 
205f7de801dSchristos /*
206fd2c82a8Schristos  * read one key from user defined input function
207fd2c82a8Schristos  */
208fd2c82a8Schristos static int
2090fd1bd62Schristos /*ARGSUSED*/
_getc_function(EditLine * el,wchar_t * c)210a7b81d12Schristos _getc_function(EditLine *el __attribute__((__unused__)), wchar_t *c)
211fd2c82a8Schristos {
212fd2c82a8Schristos 	int i;
213fd2c82a8Schristos 
214da18c738Schristos 	i = (*rl_getc_function)(rl_instream);
215fd2c82a8Schristos 	if (i == -1)
216fd2c82a8Schristos 		return 0;
217a7b81d12Schristos 	*c = (wchar_t)i;
218fd2c82a8Schristos 	return 1;
219fd2c82a8Schristos }
220fd2c82a8Schristos 
2217741aae9Schristos static void
_resize_fun(EditLine * el,void * a)2227741aae9Schristos _resize_fun(EditLine *el, void *a)
2237741aae9Schristos {
2247741aae9Schristos 	const LineInfo *li;
2255635c3c9Srillig 	const char **ap = a;
2267741aae9Schristos 
2277741aae9Schristos 	li = el_line(el);
2285635c3c9Srillig 	*ap = li->buffer;
2297741aae9Schristos }
2307741aae9Schristos 
231ea3813edSchristos static const char *
_default_history_file(void)232ea3813edSchristos _default_history_file(void)
233ea3813edSchristos {
234ea3813edSchristos 	struct passwd *p;
235e1a4fe71Schristos 	static char *path;
236e1a4fe71Schristos 	size_t len;
237ea3813edSchristos 
238e1a4fe71Schristos 	if (path)
239ea3813edSchristos 		return path;
240e1a4fe71Schristos 
241ea3813edSchristos 	if ((p = getpwuid(getuid())) == NULL)
242ea3813edSchristos 		return NULL;
243e1a4fe71Schristos 
244e1a4fe71Schristos 	len = strlen(p->pw_dir) + sizeof("/.history");
2450a0d5a75Schristos 	if ((path = el_malloc(len)) == NULL)
246e1a4fe71Schristos 		return NULL;
247e1a4fe71Schristos 
248e1a4fe71Schristos 	(void)snprintf(path, len, "%s/.history", p->pw_dir);
249ea3813edSchristos 	return path;
250ea3813edSchristos }
251fd2c82a8Schristos 
252fd2c82a8Schristos /*
253f7de801dSchristos  * READLINE compatibility stuff
254f7de801dSchristos  */
255f7de801dSchristos 
256f7de801dSchristos /*
257d052ee7bSchristos  * Set the prompt
258d052ee7bSchristos  */
259d052ee7bSchristos int
rl_set_prompt(const char * prompt)260d052ee7bSchristos rl_set_prompt(const char *prompt)
261d052ee7bSchristos {
262e6ec3d06Schristos 	char *p;
263e6ec3d06Schristos 
264d052ee7bSchristos 	if (!prompt)
265d052ee7bSchristos 		prompt = "";
266d052ee7bSchristos 	if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0)
267d052ee7bSchristos 		return 0;
268d052ee7bSchristos 	if (rl_prompt)
269b95ed37eSchristos 		el_free(rl_prompt);
270d052ee7bSchristos 	rl_prompt = strdup(prompt);
271e6ec3d06Schristos 	if (rl_prompt == NULL)
272e6ec3d06Schristos 		return -1;
273e6ec3d06Schristos 
274c790e264Schristos 	while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) {
275c790e264Schristos 		/* Remove adjacent end/start markers to avoid double-escapes. */
276c790e264Schristos 		if (p[1] == RL_PROMPT_START_IGNORE) {
277c790e264Schristos 			memmove(p, p + 2, 1 + strlen(p + 2));
278c790e264Schristos 		} else {
279e6ec3d06Schristos 			*p = RL_PROMPT_START_IGNORE;
280c790e264Schristos 		}
281c790e264Schristos 	}
282e6ec3d06Schristos 
283e6ec3d06Schristos 	return 0;
284d052ee7bSchristos }
285d052ee7bSchristos 
2860b50653eSchristos void
rl_save_prompt(void)2870b50653eSchristos rl_save_prompt(void)
2880b50653eSchristos {
2890b50653eSchristos 	rl_prompt_saved = strdup(rl_prompt);
2900b50653eSchristos }
2910b50653eSchristos 
2920b50653eSchristos void
rl_restore_prompt(void)2930b50653eSchristos rl_restore_prompt(void)
2940b50653eSchristos {
2950b50653eSchristos 	if (!rl_prompt_saved)
2960b50653eSchristos 		return;
2970b50653eSchristos 	rl_prompt = rl_prompt_saved;
2980b50653eSchristos 	rl_prompt_saved = NULL;
2990b50653eSchristos }
3000b50653eSchristos 
301d052ee7bSchristos /*
302f7de801dSchristos  * initialize rl compat stuff
303f7de801dSchristos  */
304f7de801dSchristos int
rl_initialize(void)305d30d584aSlukem rl_initialize(void)
306f7de801dSchristos {
307b3543150Schristos 	HistEvent ev;
308304ebe48Schristos 	int editmode = 1;
309304ebe48Schristos 	struct termios t;
310f7de801dSchristos 
311f7de801dSchristos 	if (e != NULL)
312f7de801dSchristos 		el_end(e);
313f7de801dSchristos 	if (h != NULL)
314b3543150Schristos 		history_end(h);
315f7de801dSchristos 
3162feacb00Schristos 	RL_UNSETSTATE(RL_STATE_DONE);
3172feacb00Schristos 
318f7de801dSchristos 	if (!rl_instream)
319f7de801dSchristos 		rl_instream = stdin;
320f7de801dSchristos 	if (!rl_outstream)
321f7de801dSchristos 		rl_outstream = stdout;
322304ebe48Schristos 
323304ebe48Schristos 	/*
324304ebe48Schristos 	 * See if we don't really want to run the editor
325304ebe48Schristos 	 */
326304ebe48Schristos 	if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0)
327304ebe48Schristos 		editmode = 0;
328304ebe48Schristos 
3290aa38cbaSchristos 	e = el_init_internal(rl_readline_name, rl_instream, rl_outstream,
3300aa38cbaSchristos 	    stderr, fileno(rl_instream), fileno(rl_outstream), fileno(stderr),
3310aa38cbaSchristos 	    NO_RESET);
332f7de801dSchristos 
333304ebe48Schristos 	if (!editmode)
334b3543150Schristos 		el_set(e, EL_EDITMODE, 0);
335304ebe48Schristos 
336b3543150Schristos 	h = history_init();
337f7de801dSchristos 	if (!e || !h)
33815a0bb6cSchristos 		return -1;
339f7de801dSchristos 
340b3543150Schristos 	history(h, &ev, H_SETSIZE, INT_MAX);	/* unlimited */
341f7de801dSchristos 	history_length = 0;
342f7de801dSchristos 	max_input_history = INT_MAX;
343f7de801dSchristos 	el_set(e, EL_HIST, history, h);
344f7de801dSchristos 
3457741aae9Schristos 	/* Setup resize function */
3467741aae9Schristos 	el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer);
3477741aae9Schristos 
348fd2c82a8Schristos 	/* setup getc function if valid */
349fd2c82a8Schristos 	if (rl_getc_function)
350fd2c82a8Schristos 		el_set(e, EL_GETCFN, _getc_function);
351fd2c82a8Schristos 
352f7de801dSchristos 	/* for proper prompt printing in readline() */
353d052ee7bSchristos 	if (rl_set_prompt("") == -1) {
354b3543150Schristos 		history_end(h);
355e6ee0301Schristos 		el_end(e);
356e6ee0301Schristos 		return -1;
357e6ee0301Schristos 	}
3589b6cb75dSchristos 	el_set(e, EL_PROMPT_ESC, _get_prompt, RL_PROMPT_START_IGNORE);
35952215a07Schristos 	el_set(e, EL_SIGNAL, rl_catch_signals);
360f7de801dSchristos 
361f7de801dSchristos 	/* set default mode to "emacs"-style and read setting afterwards */
3620749ed74Schristos 	/* so this can be overridden */
363f7de801dSchristos 	el_set(e, EL_EDITOR, "emacs");
364166e18a7Schristos 	if (rl_terminal_name != NULL)
365166e18a7Schristos 		el_set(e, EL_TERMINAL, rl_terminal_name);
366166e18a7Schristos 	else
367166e18a7Schristos 		el_get(e, EL_TERMINAL, &rl_terminal_name);
368f7de801dSchristos 
3694acffb64Sjdolecek 	/*
370552716dcSchristos 	 * Word completion - this has to go AFTER rebinding keys
3714acffb64Sjdolecek 	 * to emacs-style.
3724acffb64Sjdolecek 	 */
373f7de801dSchristos 	el_set(e, EL_ADDFN, "rl_complete",
374552716dcSchristos 	    "ReadLine compatible completion function",
375f7de801dSchristos 	    _el_rl_complete);
376f7de801dSchristos 	el_set(e, EL_BIND, "^I", "rl_complete", NULL);
377ac4e17d0Schristos 
378ac4e17d0Schristos 	/*
379ac4e17d0Schristos 	 * Send TSTP when ^Z is pressed.
380ac4e17d0Schristos 	 */
381ac4e17d0Schristos 	el_set(e, EL_ADDFN, "rl_tstp",
382ac4e17d0Schristos 	    "ReadLine compatible suspend function",
383ac4e17d0Schristos 	    _el_rl_tstp);
384ac4e17d0Schristos 	el_set(e, EL_BIND, "^Z", "rl_tstp", NULL);
385ac4e17d0Schristos 
3862f55323fSchristos 	/*
3872f55323fSchristos 	 * Set some readline compatible key-bindings.
3882f55323fSchristos 	 */
3892f55323fSchristos 	el_set(e, EL_BIND, "^R", "em-inc-search-prev", NULL);
3902f55323fSchristos 
3912f55323fSchristos 	/*
3922f55323fSchristos 	 * Allow the use of Home/End keys.
3932f55323fSchristos 	 */
3942f55323fSchristos 	el_set(e, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
3952f55323fSchristos 	el_set(e, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
3962f55323fSchristos 	el_set(e, EL_BIND, "\\e[7~", "ed-move-to-beg", NULL);
3972f55323fSchristos 	el_set(e, EL_BIND, "\\e[8~", "ed-move-to-end", NULL);
3982f55323fSchristos 	el_set(e, EL_BIND, "\\e[H", "ed-move-to-beg", NULL);
3992f55323fSchristos 	el_set(e, EL_BIND, "\\e[F", "ed-move-to-end", NULL);
4002f55323fSchristos 
4012f55323fSchristos 	/*
4022f55323fSchristos 	 * Allow the use of the Delete/Insert keys.
4032f55323fSchristos 	 */
4042f55323fSchristos 	el_set(e, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
4052f55323fSchristos 	el_set(e, EL_BIND, "\\e[2~", "ed-quoted-insert", NULL);
4062f55323fSchristos 
4072f55323fSchristos 	/*
4082f55323fSchristos 	 * Ctrl-left-arrow and Ctrl-right-arrow for word moving.
4092f55323fSchristos 	 */
4102f55323fSchristos 	el_set(e, EL_BIND, "\\e[1;5C", "em-next-word", NULL);
4112f55323fSchristos 	el_set(e, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL);
4122f55323fSchristos 	el_set(e, EL_BIND, "\\e[5C", "em-next-word", NULL);
41373f78508Smbalmer 	el_set(e, EL_BIND, "\\e[5D", "ed-prev-word", NULL);
4142f55323fSchristos 	el_set(e, EL_BIND, "\\e\\e[C", "em-next-word", NULL);
4152f55323fSchristos 	el_set(e, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL);
4162f55323fSchristos 
417f7de801dSchristos 	/* read settings from configuration file */
418f7de801dSchristos 	el_source(e, NULL);
419f7de801dSchristos 
4204acffb64Sjdolecek 	/*
4214acffb64Sjdolecek 	 * Unfortunately, some applications really do use rl_point
4224acffb64Sjdolecek 	 * and rl_line_buffer directly.
4234acffb64Sjdolecek 	 */
4247741aae9Schristos 	_resize_fun(e, &rl_line_buffer);
425af62817eSchristos 	_rl_update_pos();
426f7de801dSchristos 
427f30f759dSchristos 	tty_end(e, TCSADRAIN);
4280aa38cbaSchristos 
42915a0bb6cSchristos 	return 0;
430f7de801dSchristos }
431f7de801dSchristos 
432d30d584aSlukem 
433f7de801dSchristos /*
434f7de801dSchristos  * read one line from input stream and return it, chomping
435f7de801dSchristos  * trailing newline (if there is any)
436f7de801dSchristos  */
437f7de801dSchristos char *
readline(const char * p)4386b8a7930Schristos readline(const char *p)
439f7de801dSchristos {
440b3543150Schristos 	HistEvent ev;
4416b8a7930Schristos 	const char * volatile prompt = p;
442142a4c50Sthorpej 	int count;
443f7de801dSchristos 	const char *ret;
4440e0ac6b7Schristos 	char *buf;
4455d79eff8Schristos 	static int used_event_hook;
446f7de801dSchristos 
447f7de801dSchristos 	if (e == NULL || h == NULL)
448f7de801dSchristos 		rl_initialize();
449c94acde6Schristos 	if (rl_startup_hook) {
4506beb6f38Schristos 		(*rl_startup_hook)();
451cfd23e7aSchristos 	}
4520aa38cbaSchristos 	tty_init(e);
453cfd23e7aSchristos 
454f7de801dSchristos 
4555d79eff8Schristos 	rl_done = 0;
4565d79eff8Schristos 
4576b8a7930Schristos 	(void)setjmp(topbuf);
4580aa38cbaSchristos 	buf = NULL;
4596b8a7930Schristos 
460833166a2Sjdolecek 	/* update prompt accordingly to what has been passed */
461d052ee7bSchristos 	if (rl_set_prompt(prompt) == -1)
4620aa38cbaSchristos 		goto out;
463166e18a7Schristos 
464166e18a7Schristos 	if (rl_pre_input_hook)
4656beb6f38Schristos 		(*rl_pre_input_hook)();
466166e18a7Schristos 
4675d79eff8Schristos 	if (rl_event_hook && !(e->el_flags & NO_TTY)) {
4685d79eff8Schristos 		el_set(e, EL_GETCFN, _rl_event_read_char);
4695d79eff8Schristos 		used_event_hook = 1;
4705d79eff8Schristos 	}
4715d79eff8Schristos 
4725d79eff8Schristos 	if (!rl_event_hook && used_event_hook) {
4735d79eff8Schristos 		el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN);
4745d79eff8Schristos 		used_event_hook = 0;
4755d79eff8Schristos 	}
4765d79eff8Schristos 
477166e18a7Schristos 	rl_already_prompted = 0;
478166e18a7Schristos 
479f7de801dSchristos 	/* get one line from input stream */
480f7de801dSchristos 	ret = el_gets(e, &count);
481f7de801dSchristos 
482f7de801dSchristos 	if (ret && count > 0) {
483c88d35a3Schristos 		int lastidx;
484c88d35a3Schristos 
4850e0ac6b7Schristos 		buf = strdup(ret);
486e6ee0301Schristos 		if (buf == NULL)
4870aa38cbaSchristos 			goto out;
48810e205d7Schristos 		lastidx = count - 1;
48910e205d7Schristos 		if (buf[lastidx] == '\n')
49010e205d7Schristos 			buf[lastidx] = '\0';
491f7de801dSchristos 	} else
4920e0ac6b7Schristos 		buf = NULL;
493f7de801dSchristos 
494b3543150Schristos 	history(h, &ev, H_GETSIZE);
495f7de801dSchristos 	history_length = ev.num;
496f7de801dSchristos 
4970aa38cbaSchristos out:
498f30f759dSchristos 	tty_end(e, TCSADRAIN);
4990e0ac6b7Schristos 	return buf;
500f7de801dSchristos }
501f7de801dSchristos 
502f7de801dSchristos /*
503f7de801dSchristos  * history functions
504f7de801dSchristos  */
505f7de801dSchristos 
506f7de801dSchristos /*
507f7de801dSchristos  * is normally called before application starts to use
508f7de801dSchristos  * history expansion functions
509f7de801dSchristos  */
510f7de801dSchristos void
using_history(void)511d30d584aSlukem using_history(void)
512f7de801dSchristos {
513f7de801dSchristos 	if (h == NULL || e == NULL)
514f7de801dSchristos 		rl_initialize();
515357ec4e8Schristos 	history_offset = history_length;
516f7de801dSchristos }
517f7de801dSchristos 
518d30d584aSlukem 
519f7de801dSchristos /*
520f7de801dSchristos  * substitute ``what'' with ``with'', returning resulting string; if
5210acfa3bbSwiz  * globally == 1, substitutes all occurrences of what, otherwise only the
522f7de801dSchristos  * first one
523f7de801dSchristos  */
524f7de801dSchristos static char *
_rl_compat_sub(const char * str,const char * what,const char * with,int globally)525d30d584aSlukem _rl_compat_sub(const char *str, const char *what, const char *with,
526d30d584aSlukem     int globally)
527f7de801dSchristos {
5288b40dcaeSchristos 	const	char	*s;
5298b40dcaeSchristos 	char	*r, *result;
5308b40dcaeSchristos 	size_t	len, with_len, what_len;
531f7de801dSchristos 
5328b40dcaeSchristos 	len = strlen(str);
533f7de801dSchristos 	with_len = strlen(with);
534f7de801dSchristos 	what_len = strlen(what);
535f7de801dSchristos 
5368b40dcaeSchristos 	/* calculate length we need for result */
5378b40dcaeSchristos 	s = str;
5388b40dcaeSchristos 	while (*s) {
5398b40dcaeSchristos 		if (*s == *what && !strncmp(s, what, what_len)) {
5408b40dcaeSchristos 			len += with_len - what_len;
5418b40dcaeSchristos 			if (!globally)
5428b40dcaeSchristos 				break;
5438b40dcaeSchristos 			s += what_len;
5448b40dcaeSchristos 		} else
5458b40dcaeSchristos 			s++;
5468b40dcaeSchristos 	}
5475439fdddSchristos 	r = result = el_calloc(len + 1, sizeof(*r));
5488b40dcaeSchristos 	if (result == NULL)
5498b40dcaeSchristos 		return NULL;
5508b40dcaeSchristos 	s = str;
5518b40dcaeSchristos 	while (*s) {
5528b40dcaeSchristos 		if (*s == *what && !strncmp(s, what, what_len)) {
553be9e48beSchristos 			memcpy(r, with, with_len);
5548b40dcaeSchristos 			r += with_len;
5558b40dcaeSchristos 			s += what_len;
5568b40dcaeSchristos 			if (!globally) {
5578b40dcaeSchristos 				(void)strcpy(r, s);
55815a0bb6cSchristos 				return result;
5598b40dcaeSchristos 			}
5608b40dcaeSchristos 		} else
5618b40dcaeSchristos 			*r++ = *s++;
5628b40dcaeSchristos 	}
5632d18fd40Schristos 	*r = '\0';
56415a0bb6cSchristos 	return result;
565f7de801dSchristos }
566f7de801dSchristos 
5678b40dcaeSchristos static	char	*last_search_pat;	/* last !?pat[?] search pattern */
5688b40dcaeSchristos static	char	*last_search_match;	/* last !?pat[?] that matched */
5698b40dcaeSchristos 
5708b40dcaeSchristos const char *
get_history_event(const char * cmd,int * cindex,int qchar)5718b40dcaeSchristos get_history_event(const char *cmd, int *cindex, int qchar)
5728b40dcaeSchristos {
5738b40dcaeSchristos 	int idx, sign, sub, num, begin, ret;
5748b40dcaeSchristos 	size_t len;
5758b40dcaeSchristos 	char	*pat;
5768b40dcaeSchristos 	const char *rptr;
577b3543150Schristos 	HistEvent ev;
5788b40dcaeSchristos 
5798b40dcaeSchristos 	idx = *cindex;
5808b40dcaeSchristos 	if (cmd[idx++] != history_expansion_char)
58115a0bb6cSchristos 		return NULL;
5828b40dcaeSchristos 
5838b40dcaeSchristos 	/* find out which event to take */
5842d18fd40Schristos 	if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') {
585b3543150Schristos 		if (history(h, &ev, H_FIRST) != 0)
58615a0bb6cSchristos 			return NULL;
5878b40dcaeSchristos 		*cindex = cmd[idx]? (idx + 1):idx;
588b3543150Schristos 		return ev.str;
5898b40dcaeSchristos 	}
5908b40dcaeSchristos 	sign = 0;
5918b40dcaeSchristos 	if (cmd[idx] == '-') {
5928b40dcaeSchristos 		sign = 1;
5938b40dcaeSchristos 		idx++;
5948b40dcaeSchristos 	}
5958b40dcaeSchristos 
5968b40dcaeSchristos 	if ('0' <= cmd[idx] && cmd[idx] <= '9') {
597357ec4e8Schristos 		HIST_ENTRY *he;
5988b40dcaeSchristos 
5998b40dcaeSchristos 		num = 0;
6008b40dcaeSchristos 		while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') {
6018b40dcaeSchristos 			num = num * 10 + cmd[idx] - '0';
6028b40dcaeSchristos 			idx++;
6038b40dcaeSchristos 		}
6048b40dcaeSchristos 		if (sign)
605e19382c9Schristos 			num = history_length - num + history_base;
6068b40dcaeSchristos 
607357ec4e8Schristos 		if (!(he = history_get(num)))
60815a0bb6cSchristos 			return NULL;
6098b40dcaeSchristos 
6108b40dcaeSchristos 		*cindex = idx;
611357ec4e8Schristos 		return he->line;
6128b40dcaeSchristos 	}
6138b40dcaeSchristos 	sub = 0;
6148b40dcaeSchristos 	if (cmd[idx] == '?') {
6158b40dcaeSchristos 		sub = 1;
6168b40dcaeSchristos 		idx++;
6178b40dcaeSchristos 	}
6188b40dcaeSchristos 	begin = idx;
6198b40dcaeSchristos 	while (cmd[idx]) {
6208b40dcaeSchristos 		if (cmd[idx] == '\n')
6218b40dcaeSchristos 			break;
6228b40dcaeSchristos 		if (sub && cmd[idx] == '?')
6238b40dcaeSchristos 			break;
6248b40dcaeSchristos 		if (!sub && (cmd[idx] == ':' || cmd[idx] == ' '
6258b40dcaeSchristos 		    || cmd[idx] == '\t' || cmd[idx] == qchar))
6268b40dcaeSchristos 			break;
6278b40dcaeSchristos 		idx++;
6288b40dcaeSchristos 	}
629b219d9e4Schristos 	len = (size_t)idx - (size_t)begin;
6308b40dcaeSchristos 	if (sub && cmd[idx] == '?')
6318b40dcaeSchristos 		idx++;
6328b40dcaeSchristos 	if (sub && len == 0 && last_search_pat && *last_search_pat)
6338b40dcaeSchristos 		pat = last_search_pat;
6348b40dcaeSchristos 	else if (len == 0)
63515a0bb6cSchristos 		return NULL;
6368b40dcaeSchristos 	else {
6375439fdddSchristos 		if ((pat = el_calloc(len + 1, sizeof(*pat))) == NULL)
6388b40dcaeSchristos 			return NULL;
6396f1dc4e8Schristos 		(void)strlcpy(pat, cmd + begin, len + 1);
6408b40dcaeSchristos 	}
6418b40dcaeSchristos 
642b3543150Schristos 	if (history(h, &ev, H_CURR) != 0) {
6438b40dcaeSchristos 		if (pat != last_search_pat)
644b95ed37eSchristos 			el_free(pat);
64515a0bb6cSchristos 		return NULL;
6468b40dcaeSchristos 	}
6478b40dcaeSchristos 	num = ev.num;
6488b40dcaeSchristos 
6498b40dcaeSchristos 	if (sub) {
6508b40dcaeSchristos 		if (pat != last_search_pat) {
651b95ed37eSchristos 			el_free(last_search_pat);
6528b40dcaeSchristos 			last_search_pat = pat;
6538b40dcaeSchristos 		}
6548b40dcaeSchristos 		ret = history_search(pat, -1);
6558b40dcaeSchristos 	} else
6568b40dcaeSchristos 		ret = history_search_prefix(pat, -1);
6578b40dcaeSchristos 
6588b40dcaeSchristos 	if (ret == -1) {
6598b40dcaeSchristos 		/* restore to end of list on failed search */
660b3543150Schristos 		history(h, &ev, H_FIRST);
6618b40dcaeSchristos 		(void)fprintf(rl_outstream, "%s: Event not found\n", pat);
6628b40dcaeSchristos 		if (pat != last_search_pat)
663b95ed37eSchristos 			el_free(pat);
66415a0bb6cSchristos 		return NULL;
6658b40dcaeSchristos 	}
6668b40dcaeSchristos 
6678b40dcaeSchristos 	if (sub && len) {
668b95ed37eSchristos 		el_free(last_search_match);
669f2b72156Schristos 		last_search_match = strdup(pat);
6708b40dcaeSchristos 	}
6718b40dcaeSchristos 
6728b40dcaeSchristos 	if (pat != last_search_pat)
673b95ed37eSchristos 		el_free(pat);
6748b40dcaeSchristos 
675b3543150Schristos 	if (history(h, &ev, H_CURR) != 0)
67615a0bb6cSchristos 		return NULL;
6778b40dcaeSchristos 	*cindex = idx;
678b3543150Schristos 	rptr = ev.str;
6798b40dcaeSchristos 
6808b40dcaeSchristos 	/* roll back to original position */
681b3543150Schristos 	(void)history(h, &ev, H_SET, num);
6828b40dcaeSchristos 
6838b40dcaeSchristos 	return rptr;
6848b40dcaeSchristos }
685d30d584aSlukem 
686a9057495Schristos static int
getfrom(const char ** cmdp,char ** fromp,const char * search,int delim)687a9057495Schristos getfrom(const char **cmdp, char **fromp, const char *search, int delim)
688a9057495Schristos {
689a9057495Schristos 	size_t size = 16;
690a9057495Schristos 	size_t len = 0;
691a9057495Schristos 	const char *cmd = *cmdp;
692a9057495Schristos 	char *what = el_realloc(*fromp, size * sizeof(*what));
693a9057495Schristos 	if (what == NULL){
694a9057495Schristos 		el_free(*fromp);
695a9057495Schristos 		*fromp = NULL;
696a9057495Schristos 		return 0;
697a9057495Schristos 	}
698a9057495Schristos 	for (; *cmd && *cmd != delim; cmd++) {
699a9057495Schristos 		if (*cmd == '\\' && cmd[1] == delim)
700a9057495Schristos 			cmd++;
701f2b72156Schristos 		if (len - 1 >= size) {
702a9057495Schristos 			char *nwhat;
703a9057495Schristos 			nwhat = el_realloc(what, (size <<= 1) * sizeof(*nwhat));
704a9057495Schristos 			if (nwhat == NULL) {
705a9057495Schristos 				el_free(what);
706a9057495Schristos 				el_free(*fromp);
707a9057495Schristos 				*cmdp = cmd;
708a9057495Schristos 				*fromp = NULL;
709a9057495Schristos 				return 0;
710a9057495Schristos 			}
711a9057495Schristos 			what = nwhat;
712a9057495Schristos 		}
713a9057495Schristos 		what[len++] = *cmd;
714a9057495Schristos 	}
715a9057495Schristos 	what[len] = '\0';
716a9057495Schristos 	*fromp = what;
717a9057495Schristos 	*cmdp = cmd;
718a9057495Schristos 	if (*what == '\0') {
719a9057495Schristos 		el_free(what);
720a9057495Schristos 		if (search) {
721a9057495Schristos 			*fromp = strdup(search);
722a9057495Schristos 			if (*fromp == NULL) {
723a9057495Schristos 				return 0;
724a9057495Schristos 			}
725a9057495Schristos 		} else {
726a9057495Schristos 			*fromp = NULL;
727a9057495Schristos 			return -1;
728a9057495Schristos 		}
729a9057495Schristos 	}
730a9057495Schristos 	if (!*cmd) {
731a9057495Schristos 		el_free(what);
732f2b72156Schristos 		*fromp = NULL;
733a9057495Schristos 		return -1;
734a9057495Schristos 	}
735a9057495Schristos 
736a9057495Schristos 	cmd++;	/* shift after delim */
737a9057495Schristos 	*cmdp = cmd;
738a9057495Schristos 
739a9057495Schristos 	if (!*cmd) {
740a9057495Schristos 		el_free(what);
741f2b72156Schristos 		*fromp = NULL;
742a9057495Schristos 		return -1;
743a9057495Schristos 	}
744a9057495Schristos 	return 1;
745a9057495Schristos }
746a9057495Schristos 
747a9057495Schristos static int
getto(const char ** cmdp,char ** top,const char * from,int delim)748a9057495Schristos getto(const char **cmdp, char **top, const char *from, int delim)
749a9057495Schristos {
750a9057495Schristos 	size_t size = 16;
751a9057495Schristos 	size_t len = 0;
752a9057495Schristos 	size_t from_len = strlen(from);
753a9057495Schristos 	const char *cmd = *cmdp;
754a9057495Schristos 	char *with = el_realloc(*top, size * sizeof(*with));
755f2b72156Schristos 	*top = NULL;
756a9057495Schristos 	if (with == NULL)
757a9057495Schristos 		goto out;
758a9057495Schristos 
759a9057495Schristos 	for (; *cmd && *cmd != delim; cmd++) {
760a9057495Schristos 		if (len + from_len + 1 >= size) {
761a9057495Schristos 			char *nwith;
762a9057495Schristos 			size += from_len + 1;
763a9057495Schristos 			nwith = el_realloc(with, size * sizeof(*nwith));
764a9057495Schristos 			if (nwith == NULL)
765a9057495Schristos 				goto out;
766a9057495Schristos 			with = nwith;
767a9057495Schristos 		}
768a9057495Schristos 		if (*cmd == '&') {
769a9057495Schristos 			/* safe */
770a9057495Schristos 			strcpy(&with[len], from);
771a9057495Schristos 			len += from_len;
772a9057495Schristos 			continue;
773a9057495Schristos 		}
774a9057495Schristos 		if (*cmd == '\\' && (*(cmd + 1) == delim || *(cmd + 1) == '&'))
775a9057495Schristos 			cmd++;
776a9057495Schristos 		with[len++] = *cmd;
777a9057495Schristos 	}
778a9057495Schristos 	if (!*cmd)
779a9057495Schristos 		goto out;
780a9057495Schristos 	with[len] = '\0';
781a9057495Schristos 	*top = with;
782a9057495Schristos 	*cmdp = cmd;
783a9057495Schristos 	return 1;
784a9057495Schristos out:
785a9057495Schristos 	el_free(with);
786a9057495Schristos 	el_free(*top);
787a9057495Schristos 	*top = NULL;
788a9057495Schristos 	*cmdp = cmd;
789a9057495Schristos 	return -1;
790a9057495Schristos }
791a9057495Schristos 
792a9057495Schristos static void
replace(char ** tmp,int c)793a9057495Schristos replace(char **tmp, int c)
794a9057495Schristos {
795a9057495Schristos 	char *aptr;
796a9057495Schristos 	if ((aptr = strrchr(*tmp, c)) == NULL)
797a9057495Schristos 		return;
798a9057495Schristos 	aptr = strdup(aptr + 1); // XXX: check
799a9057495Schristos 	el_free(*tmp);
800a9057495Schristos 	*tmp = aptr;
801a9057495Schristos }
802a9057495Schristos 
803f7de801dSchristos /*
804f7de801dSchristos  * the real function doing history expansion - takes as argument command
805f7de801dSchristos  * to do and data upon which the command should be executed
806f7de801dSchristos  * does expansion the way I've understood readline documentation
807f7de801dSchristos  *
808f7de801dSchristos  * returns 0 if data was not modified, 1 if it was and 2 if the string
809f7de801dSchristos  * should be only printed and not executed; in case of error,
810f7de801dSchristos  * returns -1 and *result points to NULL
8117d1220acSsnj  * it's the caller's responsibility to free() the string returned in *result
812f7de801dSchristos  */
813f7de801dSchristos static int
_history_expand_command(const char * command,size_t offs,size_t cmdlen,char ** result)8148b40dcaeSchristos _history_expand_command(const char *command, size_t offs, size_t cmdlen,
8158b40dcaeSchristos     char **result)
816f7de801dSchristos {
817a9057495Schristos 	char *tmp, *search = NULL, *aptr, delim;
8188b40dcaeSchristos 	const char *ptr, *cmd;
819a0be074dSchristos 	static char *from = NULL, *to = NULL;
8208b40dcaeSchristos 	int start, end, idx, has_mods = 0;
821a9057495Schristos 	int p_on = 0, g_on = 0, ev;
822f7de801dSchristos 
823f7de801dSchristos 	*result = NULL;
8248b40dcaeSchristos 	aptr = NULL;
825391b46bcSchristos 	ptr = NULL;
826f7de801dSchristos 
8278b40dcaeSchristos 	/* First get event specifier */
8288b40dcaeSchristos 	idx = 0;
829f7de801dSchristos 
8308b40dcaeSchristos 	if (strchr(":^*$", command[offs + 1])) {
8318b40dcaeSchristos 		char str[4];
8328b40dcaeSchristos 		/*
8338b40dcaeSchristos 		* "!:" is shorthand for "!!:".
8348b40dcaeSchristos 		* "!^", "!*" and "!$" are shorthand for
8358b40dcaeSchristos 		* "!!:^", "!!:*" and "!!:$" respectively.
8368b40dcaeSchristos 		*/
8378b40dcaeSchristos 		str[0] = str[1] = '!';
8388b40dcaeSchristos 		str[2] = '0';
8398b40dcaeSchristos 		ptr = get_history_event(str, &idx, 0);
8408b40dcaeSchristos 		idx = (command[offs + 1] == ':')? 1:0;
8418b40dcaeSchristos 		has_mods = 1;
8428b40dcaeSchristos 	} else {
8438b40dcaeSchristos 		if (command[offs + 1] == '#') {
8448b40dcaeSchristos 			/* use command so far */
8455439fdddSchristos 			if ((aptr = el_calloc(offs + 1, sizeof(*aptr)))
846b95ed37eSchristos 			    == NULL)
8478b40dcaeSchristos 				return -1;
8486f1dc4e8Schristos 			(void)strlcpy(aptr, command, offs + 1);
849f7de801dSchristos 			idx = 1;
850f7de801dSchristos 		} else {
8518b40dcaeSchristos 			int	qchar;
852f7de801dSchristos 
853289e70c6Srillig 			qchar = (offs > 0 && command[offs - 1] == '"')
854289e70c6Srillig 			    ? '"' : '\0';
8558b40dcaeSchristos 			ptr = get_history_event(command + offs, &idx, qchar);
856f7de801dSchristos 		}
857b219d9e4Schristos 		has_mods = command[offs + (size_t)idx] == ':';
858f7de801dSchristos 	}
859f7de801dSchristos 
8608b40dcaeSchristos 	if (ptr == NULL && aptr == NULL)
86115a0bb6cSchristos 		return -1;
862f7de801dSchristos 
8638b40dcaeSchristos 	if (!has_mods) {
8648b40dcaeSchristos 		*result = strdup(aptr ? aptr : ptr);
8658b40dcaeSchristos 		if (aptr)
866b95ed37eSchristos 			el_free(aptr);
867ea3813edSchristos 		if (*result == NULL)
868ea3813edSchristos 			return -1;
86915a0bb6cSchristos 		return 1;
8708b40dcaeSchristos 	}
871f7de801dSchristos 
8728b40dcaeSchristos 	cmd = command + offs + idx + 1;
8738b40dcaeSchristos 
8748b40dcaeSchristos 	/* Now parse any word designators */
8758b40dcaeSchristos 
8768b40dcaeSchristos 	if (*cmd == '%')	/* last word matched by ?pat? */
8778b40dcaeSchristos 		tmp = strdup(last_search_match ? last_search_match : "");
8788b40dcaeSchristos 	else if (strchr("^*$-0123456789", *cmd)) {
8798b40dcaeSchristos 		start = end = -1;
880f7de801dSchristos 		if (*cmd == '^')
881f7de801dSchristos 			start = end = 1, cmd++;
882f7de801dSchristos 		else if (*cmd == '$')
8838b40dcaeSchristos 			start = -1, cmd++;
884f7de801dSchristos 		else if (*cmd == '*')
8858b40dcaeSchristos 			start = 1, cmd++;
8868b40dcaeSchristos 		else if (*cmd == '-' || isdigit((unsigned char) *cmd)) {
8878b40dcaeSchristos 			start = 0;
8888b40dcaeSchristos 			while (*cmd && '0' <= *cmd && *cmd <= '9')
8898b40dcaeSchristos 				start = start * 10 + *cmd++ - '0';
890f7de801dSchristos 
8918b40dcaeSchristos 			if (*cmd == '-') {
8928b40dcaeSchristos 				if (isdigit((unsigned char) cmd[1])) {
8938b40dcaeSchristos 					cmd++;
8948b40dcaeSchristos 					end = 0;
8958b40dcaeSchristos 					while (*cmd && '0' <= *cmd && *cmd <= '9')
8968b40dcaeSchristos 						end = end * 10 + *cmd++ - '0';
8978b40dcaeSchristos 				} else if (cmd[1] == '$') {
8988b40dcaeSchristos 					cmd += 2;
8998b40dcaeSchristos 					end = -1;
9008b40dcaeSchristos 				} else {
9018b40dcaeSchristos 					cmd++;
902f7de801dSchristos 					end = -2;
903f7de801dSchristos 				}
9048b40dcaeSchristos 			} else if (*cmd == '*')
905f7de801dSchristos 				end = -1, cmd++;
9068b40dcaeSchristos 			else
907f7de801dSchristos 				end = start;
908f7de801dSchristos 		}
9098b40dcaeSchristos 		tmp = history_arg_extract(start, end, aptr? aptr:ptr);
9108b40dcaeSchristos 		if (tmp == NULL) {
9118b40dcaeSchristos 			(void)fprintf(rl_outstream, "%s: Bad word specifier",
9128b40dcaeSchristos 			    command + offs + idx);
9138b40dcaeSchristos 			if (aptr)
914b95ed37eSchristos 				el_free(aptr);
91515a0bb6cSchristos 			return -1;
9168b40dcaeSchristos 		}
9178b40dcaeSchristos 	} else
9188b40dcaeSchristos 		tmp = strdup(aptr? aptr:ptr);
919f7de801dSchristos 
9208b40dcaeSchristos 	if (aptr)
921b95ed37eSchristos 		el_free(aptr);
9228b40dcaeSchristos 
923a06595c2Slukem 	if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) {
9248b40dcaeSchristos 		*result = tmp;
92515a0bb6cSchristos 		return 1;
9268b40dcaeSchristos 	}
9278b40dcaeSchristos 
928f7de801dSchristos 	for (; *cmd; cmd++) {
929a9057495Schristos 		switch (*cmd) {
930a9057495Schristos 		case ':':
931f7de801dSchristos 			continue;
932a9057495Schristos 		case 'h':	/* remove trailing path */
9338b40dcaeSchristos 			if ((aptr = strrchr(tmp, '/')) != NULL)
9342d18fd40Schristos 				*aptr = '\0';
935a9057495Schristos 			continue;
936a9057495Schristos 		case 't':	/* remove leading path */
937a9057495Schristos 			replace(&tmp, '/');
938a9057495Schristos 			continue;
939a9057495Schristos 		case 'r':	/* remove trailing suffix */
9408b40dcaeSchristos 			if ((aptr = strrchr(tmp, '.')) != NULL)
9412d18fd40Schristos 				*aptr = '\0';
942a9057495Schristos 			continue;
943a9057495Schristos 		case 'e':	/* remove all but suffix */
944a9057495Schristos 			replace(&tmp, '.');
945a9057495Schristos 			continue;
946a9057495Schristos 		case 'p':	/* print only */
9478b40dcaeSchristos 			p_on = 1;
948a9057495Schristos 			continue;
949a9057495Schristos 		case 'g':
950f7de801dSchristos 			g_on = 2;
951f7de801dSchristos 			continue;
952a9057495Schristos 		case '&':
953a9057495Schristos 			if (from == NULL || to == NULL)
954f7de801dSchristos 				continue;
955a9057495Schristos 			/*FALLTHROUGH*/
956a9057495Schristos 		case 's':
957f2b72156Schristos 			ev = -1;
958f2b72156Schristos 			delim = *++cmd;
959f2b72156Schristos 			if (delim == '\0' || *++cmd == '\0')
960f2b72156Schristos 				goto out;
961f2b72156Schristos 			if ((ev = getfrom(&cmd, &from, search, delim)) != 1)
962f2b72156Schristos 				goto out;
963f2b72156Schristos 			if ((ev = getto(&cmd, &to, from, delim)) != 1)
964f2b72156Schristos 				goto out;
9658b40dcaeSchristos 			aptr = _rl_compat_sub(tmp, from, to, g_on);
9668b40dcaeSchristos 			if (aptr) {
967b95ed37eSchristos 				el_free(tmp);
9688b40dcaeSchristos 				tmp = aptr;
969a17c7fe4Schristos 			}
970f7de801dSchristos 			g_on = 0;
971f2b72156Schristos 			cmd--;
972a9057495Schristos 			continue;
973f7de801dSchristos 		}
974f7de801dSchristos 	}
9758b40dcaeSchristos 	*result = tmp;
97615a0bb6cSchristos 	return p_on ? 2 : 1;
977f2b72156Schristos out:
978f2b72156Schristos 	el_free(tmp);
979f2b72156Schristos 	return ev;
980f2b72156Schristos 
981f7de801dSchristos }
982f7de801dSchristos 
983d30d584aSlukem 
984f7de801dSchristos /*
985f7de801dSchristos  * csh-style history expansion
986f7de801dSchristos  */
987f7de801dSchristos int
history_expand(char * str,char ** output)988d30d584aSlukem history_expand(char *str, char **output)
989f7de801dSchristos {
9908b40dcaeSchristos 	int ret = 0;
9918b40dcaeSchristos 	size_t idx, i, size;
9928b40dcaeSchristos 	char *tmp, *result;
993f7de801dSchristos 
994f7de801dSchristos 	if (h == NULL || e == NULL)
995f7de801dSchristos 		rl_initialize();
996f7de801dSchristos 
9978b40dcaeSchristos 	if (history_expansion_char == 0) {
9988b40dcaeSchristos 		*output = strdup(str);
99915a0bb6cSchristos 		return 0;
10008b40dcaeSchristos 	}
1001f7de801dSchristos 
10028b40dcaeSchristos 	*output = NULL;
1003f7de801dSchristos 	if (str[0] == history_subst_char) {
1004f7de801dSchristos 		/* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
10055439fdddSchristos 		*output = el_calloc(strlen(str) + 4 + 1, sizeof(**output));
10068b40dcaeSchristos 		if (*output == NULL)
10078b40dcaeSchristos 			return 0;
10088b40dcaeSchristos 		(*output)[0] = (*output)[1] = history_expansion_char;
10098b40dcaeSchristos 		(*output)[2] = ':';
10108b40dcaeSchristos 		(*output)[3] = 's';
10118b40dcaeSchristos 		(void)strcpy((*output) + 4, str);
10128b40dcaeSchristos 		str = *output;
10138b40dcaeSchristos 	} else {
10148b40dcaeSchristos 		*output = strdup(str);
10158b40dcaeSchristos 		if (*output == NULL)
10168b40dcaeSchristos 			return 0;
1017f7de801dSchristos 	}
10188b40dcaeSchristos 
1019c5f39d86Schristos #define ADD_STRING(what, len, fr)					\
1020f7de801dSchristos 	{								\
1021e6ee0301Schristos 		if (idx + len + 1 > size) {				\
1022b95ed37eSchristos 			char *nresult = el_realloc(result,		\
1023b95ed37eSchristos 			    (size += len + 1) * sizeof(*nresult));	\
1024e6ee0301Schristos 			if (nresult == NULL) {				\
1025b95ed37eSchristos 				el_free(*output);			\
10268a221746Srillig 				el_free(fr);				\
10271d6595e5Schristos 				return 0;				\
1028e6ee0301Schristos 			}						\
1029e6ee0301Schristos 			result = nresult;				\
1030e6ee0301Schristos 		}							\
10316f1dc4e8Schristos 		(void)strlcpy(&result[idx], what, len + 1);		\
1032f7de801dSchristos 		idx += len;						\
1033f7de801dSchristos 	}
1034f7de801dSchristos 
1035f7de801dSchristos 	result = NULL;
1036f7de801dSchristos 	size = idx = 0;
1037c66ab9a1Schristos 	tmp = NULL;
1038f7de801dSchristos 	for (i = 0; str[i];) {
10398b40dcaeSchristos 		int qchar, loop_again;
10408b40dcaeSchristos 		size_t len, start, j;
1041f7de801dSchristos 
10428b40dcaeSchristos 		qchar = 0;
1043f7de801dSchristos 		loop_again = 1;
1044f7de801dSchristos 		start = j = i;
1045f7de801dSchristos loop:
1046f7de801dSchristos 		for (; str[j]; j++) {
1047f7de801dSchristos 			if (str[j] == '\\' &&
1048f7de801dSchristos 			    str[j + 1] == history_expansion_char) {
10498b1185ccSchristos 				len = strlen(&str[j + 1]) + 1;
10508b1185ccSchristos 				memmove(&str[j], &str[j + 1], len);
1051f7de801dSchristos 				continue;
1052f7de801dSchristos 			}
1053f7de801dSchristos 			if (!loop_again) {
10548b40dcaeSchristos 				if (isspace((unsigned char) str[j])
10558b40dcaeSchristos 				    || str[j] == qchar)
1056f7de801dSchristos 					break;
1057f7de801dSchristos 			}
1058f7de801dSchristos 			if (str[j] == history_expansion_char
1059f7de801dSchristos 			    && !strchr(history_no_expand_chars, str[j + 1])
1060f7de801dSchristos 			    && (!history_inhibit_expansion_function ||
10618b40dcaeSchristos 			    (*history_inhibit_expansion_function)(str,
10628b40dcaeSchristos 			    (int)j) == 0))
1063f7de801dSchristos 				break;
1064f7de801dSchristos 		}
1065f7de801dSchristos 
10668b40dcaeSchristos 		if (str[j] && loop_again) {
1067f7de801dSchristos 			i = j;
10688b40dcaeSchristos 			qchar = (j > 0 && str[j - 1] == '"' )? '"':0;
1069f7de801dSchristos 			j++;
1070f7de801dSchristos 			if (str[j] == history_expansion_char)
1071f7de801dSchristos 				j++;
1072f7de801dSchristos 			loop_again = 0;
1073f7de801dSchristos 			goto loop;
1074f7de801dSchristos 		}
1075f7de801dSchristos 		len = i - start;
10768a221746Srillig 		ADD_STRING(&str[start], len, NULL);
1077f7de801dSchristos 
10788b40dcaeSchristos 		if (str[i] == '\0' || str[i] != history_expansion_char) {
1079f7de801dSchristos 			len = j - i;
10808a221746Srillig 			ADD_STRING(&str[i], len, NULL);
1081f7de801dSchristos 			if (start == 0)
10828b40dcaeSchristos 				ret = 0;
1083f7de801dSchristos 			else
10848b40dcaeSchristos 				ret = 1;
1085f7de801dSchristos 			break;
1086f7de801dSchristos 		}
10878b40dcaeSchristos 		ret = _history_expand_command (str, i, (j - i), &tmp);
10888b40dcaeSchristos 		if (ret > 0 && tmp) {
10898b40dcaeSchristos 			len = strlen(tmp);
10908a221746Srillig 			ADD_STRING(tmp, len, tmp);
10914baec303Schristos 		}
10924baec303Schristos 		if (tmp) {
1093b95ed37eSchristos 			el_free(tmp);
1094c66ab9a1Schristos 			tmp = NULL;
1095f7de801dSchristos 		}
1096f7de801dSchristos 		i = j;
10978b40dcaeSchristos 	}
1098f7de801dSchristos 
10998b40dcaeSchristos 	/* ret is 2 for "print only" option */
11008b40dcaeSchristos 	if (ret == 2) {
11018b40dcaeSchristos 		add_history(result);
1102f7de801dSchristos #ifdef GDB_411_HACK
1103f7de801dSchristos 		/* gdb 4.11 has been shipped with readline, where */
1104f7de801dSchristos 		/* history_expand() returned -1 when the line	  */
1105f7de801dSchristos 		/* should not be executed; in readline 2.1+	  */
1106f7de801dSchristos 		/* it should return 2 in such a case		  */
11078b40dcaeSchristos 		ret = -1;
1108f7de801dSchristos #endif
1109f7de801dSchristos 	}
1110b95ed37eSchristos 	el_free(*output);
1111f7de801dSchristos 	*output = result;
1112f7de801dSchristos 
111315a0bb6cSchristos 	return ret;
1114f7de801dSchristos }
1115f7de801dSchristos 
11168b40dcaeSchristos /*
11178b40dcaeSchristos * Return a string consisting of arguments of "str" from "start" to "end".
11188b40dcaeSchristos */
11198b40dcaeSchristos char *
history_arg_extract(int start,int end,const char * str)11208b40dcaeSchristos history_arg_extract(int start, int end, const char *str)
11218b40dcaeSchristos {
11228b40dcaeSchristos 	size_t  i, len, max;
1123cfa16c63Schristos 	char	**arr, *result = NULL;
11248b40dcaeSchristos 
11258b40dcaeSchristos 	arr = history_tokenize(str);
11268b40dcaeSchristos 	if (!arr)
1127cfa16c63Schristos 		return NULL;
1128cfa16c63Schristos 	if (arr && *arr == NULL)
1129cfa16c63Schristos 		goto out;
11308b40dcaeSchristos 
11318b40dcaeSchristos 	for (max = 0; arr[max]; max++)
11328b40dcaeSchristos 		continue;
11338b40dcaeSchristos 	max--;
11348b40dcaeSchristos 
11358b40dcaeSchristos 	if (start == '$')
11365c894153Schristos 		start = (int)max;
11378b40dcaeSchristos 	if (end == '$')
11385c894153Schristos 		end = (int)max;
11398b40dcaeSchristos 	if (end < 0)
11405c894153Schristos 		end = (int)max + end + 1;
11418b40dcaeSchristos 	if (start < 0)
11428b40dcaeSchristos 		start = end;
11438b40dcaeSchristos 
1144cfa16c63Schristos 	if (start < 0 || end < 0 || (size_t)start > max ||
1145cfa16c63Schristos 	    (size_t)end > max || start > end)
1146cfa16c63Schristos 		goto out;
11478b40dcaeSchristos 
1148b219d9e4Schristos 	for (i = (size_t)start, len = 0; i <= (size_t)end; i++)
11498b40dcaeSchristos 		len += strlen(arr[i]) + 1;
11508b40dcaeSchristos 	len++;
11515439fdddSchristos 	result = el_calloc(len, sizeof(*result));
11528b40dcaeSchristos 	if (result == NULL)
1153cfa16c63Schristos 		goto out;
11548b40dcaeSchristos 
1155b219d9e4Schristos 	for (i = (size_t)start, len = 0; i <= (size_t)end; i++) {
11568b40dcaeSchristos 		(void)strcpy(result + len, arr[i]);
11578b40dcaeSchristos 		len += strlen(arr[i]);
1158a06595c2Slukem 		if (i < (size_t)end)
11598b40dcaeSchristos 			result[len++] = ' ';
11608b40dcaeSchristos 	}
11612d18fd40Schristos 	result[len] = '\0';
11628b40dcaeSchristos 
1163cfa16c63Schristos out:
11648b40dcaeSchristos 	for (i = 0; arr[i]; i++)
1165b95ed37eSchristos 		el_free(arr[i]);
1166b95ed37eSchristos 	el_free(arr);
11678b40dcaeSchristos 
1168cfa16c63Schristos 	return result;
11698b40dcaeSchristos }
1170d30d584aSlukem 
1171f7de801dSchristos /*
11728b40dcaeSchristos  * Parse the string into individual tokens,
11738b40dcaeSchristos  * similar to how shell would do it.
1174f7de801dSchristos  */
1175f7de801dSchristos char **
history_tokenize(const char * str)1176d30d584aSlukem history_tokenize(const char *str)
1177f7de801dSchristos {
11788b40dcaeSchristos 	int size = 1, idx = 0, i, start;
1179a0be074dSchristos 	size_t len;
1180f7de801dSchristos 	char **result = NULL, *temp, delim = '\0';
1181f7de801dSchristos 
11828b40dcaeSchristos 	for (i = 0; str[i];) {
118396c91584Schristos 		while (isspace((unsigned char) str[i]))
1184f7de801dSchristos 			i++;
1185f7de801dSchristos 		start = i;
11868b40dcaeSchristos 		for (; str[i];) {
1187833166a2Sjdolecek 			if (str[i] == '\\') {
1188939ac125Sjdolecek 				if (str[i+1] != '\0')
1189f7de801dSchristos 					i++;
1190833166a2Sjdolecek 			} else if (str[i] == delim)
1191f7de801dSchristos 				delim = '\0';
1192f7de801dSchristos 			else if (!delim &&
119396c91584Schristos 				    (isspace((unsigned char) str[i]) ||
119496c91584Schristos 				strchr("()<>;&|$", str[i])))
1195f7de801dSchristos 				break;
1196f7de801dSchristos 			else if (!delim && strchr("'`\"", str[i]))
1197f7de801dSchristos 				delim = str[i];
11988b40dcaeSchristos 			if (str[i])
11998b40dcaeSchristos 				i++;
1200f7de801dSchristos 		}
1201f7de801dSchristos 
12028b40dcaeSchristos 		if (idx + 2 >= size) {
1203e6ee0301Schristos 			char **nresult;
1204f7de801dSchristos 			size <<= 1;
1205b219d9e4Schristos 			nresult = el_realloc(result, (size_t)size * sizeof(*nresult));
1206e6ee0301Schristos 			if (nresult == NULL) {
1207b95ed37eSchristos 				el_free(result);
1208e6ee0301Schristos 				return NULL;
1209e6ee0301Schristos 			}
1210e6ee0301Schristos 			result = nresult;
1211f7de801dSchristos 		}
1212b219d9e4Schristos 		len = (size_t)i - (size_t)start;
12135439fdddSchristos 		temp = el_calloc(len + 1, sizeof(*temp));
1214e6ee0301Schristos 		if (temp == NULL) {
12158b40dcaeSchristos 			for (i = 0; i < idx; i++)
1216b95ed37eSchristos 				el_free(result[i]);
1217b95ed37eSchristos 			el_free(result);
1218e6ee0301Schristos 			return NULL;
1219e6ee0301Schristos 		}
12206f1dc4e8Schristos 		(void)strlcpy(temp, &str[start], len + 1);
12218b40dcaeSchristos 		result[idx++] = temp;
12228b40dcaeSchristos 		result[idx] = NULL;
12238b40dcaeSchristos 		if (str[i])
12248b40dcaeSchristos 			i++;
1225f7de801dSchristos 	}
122615a0bb6cSchristos 	return result;
1227f7de801dSchristos }
1228f7de801dSchristos 
1229d30d584aSlukem 
1230f7de801dSchristos /*
1231f7de801dSchristos  * limit size of history record to ``max'' events
1232f7de801dSchristos  */
1233f7de801dSchristos void
stifle_history(int max)1234d30d584aSlukem stifle_history(int max)
1235f7de801dSchristos {
1236b3543150Schristos 	HistEvent ev;
1237c6a70e7fSchristos 	HIST_ENTRY *he;
1238f7de801dSchristos 
1239f7de801dSchristos 	if (h == NULL || e == NULL)
1240f7de801dSchristos 		rl_initialize();
1241f7de801dSchristos 
1242c6a70e7fSchristos 	if (history(h, &ev, H_SETSIZE, max) == 0) {
1243f7de801dSchristos 		max_input_history = max;
124483d95411Schristos 		if (history_length > max)
124583d95411Schristos 			history_base = history_length - max;
1246e0349677Schristos 		while (history_length > max) {
1247426b9c73Schristos 			he = remove_history(0);
1248c6a70e7fSchristos 			el_free(he->data);
1249c6a70e7fSchristos 			el_free((void *)(unsigned long)he->line);
1250c6a70e7fSchristos 			el_free(he);
1251c6a70e7fSchristos 		}
1252c6a70e7fSchristos 	}
1253f7de801dSchristos }
1254f7de801dSchristos 
1255d30d584aSlukem 
1256f7de801dSchristos /*
1257f7de801dSchristos  * "unlimit" size of history - set the limit to maximum allowed int value
1258f7de801dSchristos  */
1259f7de801dSchristos int
unstifle_history(void)1260d30d584aSlukem unstifle_history(void)
1261f7de801dSchristos {
1262b3543150Schristos 	HistEvent ev;
1263f7de801dSchristos 	int omax;
1264f7de801dSchristos 
1265b3543150Schristos 	history(h, &ev, H_SETSIZE, INT_MAX);
1266f7de801dSchristos 	omax = max_input_history;
1267f7de801dSchristos 	max_input_history = INT_MAX;
126815a0bb6cSchristos 	return omax;		/* some value _must_ be returned */
1269f7de801dSchristos }
1270f7de801dSchristos 
1271d30d584aSlukem 
1272f7de801dSchristos int
history_is_stifled(void)1273d30d584aSlukem history_is_stifled(void)
1274f7de801dSchristos {
1275d30d584aSlukem 
1276f7de801dSchristos 	/* cannot return true answer */
127715a0bb6cSchristos 	return max_input_history != INT_MAX;
1278f7de801dSchristos }
1279f7de801dSchristos 
1280ea3813edSchristos static const char _history_tmp_template[] = "/tmp/.historyXXXXXX";
1281ea3813edSchristos 
1282ea3813edSchristos int
history_truncate_file(const char * filename,int nlines)1283ea3813edSchristos history_truncate_file (const char *filename, int nlines)
1284ea3813edSchristos {
1285ea3813edSchristos 	int ret = 0;
1286ea3813edSchristos 	FILE *fp, *tp;
1287ea3813edSchristos 	char template[sizeof(_history_tmp_template)];
1288ea3813edSchristos 	char buf[4096];
1289ea3813edSchristos 	int fd;
1290ea3813edSchristos 	char *cp;
1291ea3813edSchristos 	off_t off;
1292ea3813edSchristos 	int count = 0;
1293ea3813edSchristos 	ssize_t left = 0;
1294ea3813edSchristos 
1295ea3813edSchristos 	if (filename == NULL && (filename = _default_history_file()) == NULL)
1296ea3813edSchristos 		return errno;
1297ea3813edSchristos 	if ((fp = fopen(filename, "r+")) == NULL)
1298ea3813edSchristos 		return errno;
1299ea3813edSchristos 	strcpy(template, _history_tmp_template);
1300ea3813edSchristos 	if ((fd = mkstemp(template)) == -1) {
1301ea3813edSchristos 		ret = errno;
1302ea3813edSchristos 		goto out1;
1303ea3813edSchristos 	}
1304ea3813edSchristos 
1305ea3813edSchristos 	if ((tp = fdopen(fd, "r+")) == NULL) {
1306ea3813edSchristos 		close(fd);
1307ea3813edSchristos 		ret = errno;
1308ea3813edSchristos 		goto out2;
1309ea3813edSchristos 	}
1310ea3813edSchristos 
1311ea3813edSchristos 	for(;;) {
1312034e7c54Schristos 		if (fread(buf, sizeof(buf), (size_t)1, fp) != 1) {
1313ea3813edSchristos 			if (ferror(fp)) {
1314ea3813edSchristos 				ret = errno;
1315ea3813edSchristos 				break;
1316ea3813edSchristos 			}
1317ea3813edSchristos 			if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) ==
1318ea3813edSchristos 			    (off_t)-1) {
1319ea3813edSchristos 				ret = errno;
1320ea3813edSchristos 				break;
1321ea3813edSchristos 			}
1322b219d9e4Schristos 			left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), fp);
1323ea3813edSchristos 			if (ferror(fp)) {
1324ea3813edSchristos 				ret = errno;
1325ea3813edSchristos 				break;
1326ea3813edSchristos 			}
1327ea3813edSchristos 			if (left == 0) {
1328ea3813edSchristos 				count--;
1329ea3813edSchristos 				left = sizeof(buf);
1330034e7c54Schristos 			} else if (fwrite(buf, (size_t)left, (size_t)1, tp)
1331034e7c54Schristos 			    != 1) {
1332ea3813edSchristos 				ret = errno;
1333ea3813edSchristos 				break;
1334ea3813edSchristos 			}
1335ea3813edSchristos 			fflush(tp);
1336ea3813edSchristos 			break;
1337ea3813edSchristos 		}
1338034e7c54Schristos 		if (fwrite(buf, sizeof(buf), (size_t)1, tp) != 1) {
1339ea3813edSchristos 			ret = errno;
1340ea3813edSchristos 			break;
1341ea3813edSchristos 		}
1342ea3813edSchristos 		count++;
1343ea3813edSchristos 	}
1344ea3813edSchristos 	if (ret)
1345ea3813edSchristos 		goto out3;
1346ea3813edSchristos 	cp = buf + left - 1;
1347ea3813edSchristos 	if(*cp != '\n')
1348ea3813edSchristos 		cp++;
1349ea3813edSchristos 	for(;;) {
1350ea3813edSchristos 		while (--cp >= buf) {
1351ea3813edSchristos 			if (*cp == '\n') {
1352ea3813edSchristos 				if (--nlines == 0) {
1353ea3813edSchristos 					if (++cp >= buf + sizeof(buf)) {
1354ea3813edSchristos 						count++;
1355ea3813edSchristos 						cp = buf;
1356ea3813edSchristos 					}
1357ea3813edSchristos 					break;
1358ea3813edSchristos 				}
1359ea3813edSchristos 			}
1360ea3813edSchristos 		}
1361ea3813edSchristos 		if (nlines <= 0 || count == 0)
1362ea3813edSchristos 			break;
1363ea3813edSchristos 		count--;
1364ea3813edSchristos 		if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) {
1365ea3813edSchristos 			ret = errno;
1366ea3813edSchristos 			break;
1367ea3813edSchristos 		}
1368034e7c54Schristos 		if (fread(buf, sizeof(buf), (size_t)1, tp) != 1) {
1369ea3813edSchristos 			if (ferror(tp)) {
1370ea3813edSchristos 				ret = errno;
1371ea3813edSchristos 				break;
1372ea3813edSchristos 			}
1373ea3813edSchristos 			ret = EAGAIN;
1374ea3813edSchristos 			break;
1375ea3813edSchristos 		}
1376ea3813edSchristos 		cp = buf + sizeof(buf);
1377ea3813edSchristos 	}
1378ea3813edSchristos 
1379ea3813edSchristos 	if (ret || nlines > 0)
1380ea3813edSchristos 		goto out3;
1381ea3813edSchristos 
1382034e7c54Schristos 	if (fseeko(fp, (off_t)0, SEEK_SET) == (off_t)-1) {
1383ea3813edSchristos 		ret = errno;
1384ea3813edSchristos 		goto out3;
1385ea3813edSchristos 	}
1386ea3813edSchristos 
1387ea3813edSchristos 	if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) ==
1388ea3813edSchristos 	    (off_t)-1) {
1389ea3813edSchristos 		ret = errno;
1390ea3813edSchristos 		goto out3;
1391ea3813edSchristos 	}
1392ea3813edSchristos 
1393ea3813edSchristos 	for(;;) {
1394b219d9e4Schristos 		if ((left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), tp)) == 0) {
1395ea3813edSchristos 			if (ferror(fp))
1396ea3813edSchristos 				ret = errno;
1397ea3813edSchristos 			break;
1398ea3813edSchristos 		}
1399034e7c54Schristos 		if (fwrite(buf, (size_t)left, (size_t)1, fp) != 1) {
1400ea3813edSchristos 			ret = errno;
1401ea3813edSchristos 			break;
1402ea3813edSchristos 		}
1403ea3813edSchristos 	}
1404ea3813edSchristos 	fflush(fp);
1405ea3813edSchristos 	if((off = ftello(fp)) > 0)
1406ea3813edSchristos 		(void)ftruncate(fileno(fp), off);
1407ea3813edSchristos out3:
1408ea3813edSchristos 	fclose(tp);
1409ea3813edSchristos out2:
1410ea3813edSchristos 	unlink(template);
1411ea3813edSchristos out1:
1412ea3813edSchristos 	fclose(fp);
1413ea3813edSchristos 
1414ea3813edSchristos 	return ret;
1415ea3813edSchristos }
1416ea3813edSchristos 
1417d30d584aSlukem 
1418f7de801dSchristos /*
1419f7de801dSchristos  * read history from a file given
1420f7de801dSchristos  */
1421f7de801dSchristos int
read_history(const char * filename)1422d30d584aSlukem read_history(const char *filename)
1423f7de801dSchristos {
1424b3543150Schristos 	HistEvent ev;
1425f7de801dSchristos 
1426f7de801dSchristos 	if (h == NULL || e == NULL)
1427f7de801dSchristos 		rl_initialize();
1428ea3813edSchristos 	if (filename == NULL && (filename = _default_history_file()) == NULL)
1429ea3813edSchristos 		return errno;
143073333e56Skre 	errno = 0;
143173333e56Skre 	if (history(h, &ev, H_LOAD, filename) == -1)
143273333e56Skre 		return errno ? errno : EINVAL;
143373333e56Skre 	if (history(h, &ev, H_GETSIZE) == 0)
143473333e56Skre 		history_length = ev.num;
143573333e56Skre 	if (history_length < 0)
143673333e56Skre 		return EINVAL;
143773333e56Skre 	return 0;
1438f7de801dSchristos }
1439f7de801dSchristos 
1440d30d584aSlukem 
1441f7de801dSchristos /*
1442f7de801dSchristos  * write history to a file given
1443f7de801dSchristos  */
1444f7de801dSchristos int
write_history(const char * filename)1445d30d584aSlukem write_history(const char *filename)
1446f7de801dSchristos {
1447b3543150Schristos 	HistEvent ev;
1448f7de801dSchristos 
1449f7de801dSchristos 	if (h == NULL || e == NULL)
1450f7de801dSchristos 		rl_initialize();
1451ea3813edSchristos 	if (filename == NULL && (filename = _default_history_file()) == NULL)
1452ea3813edSchristos 		return errno;
145315a0bb6cSchristos 	return history(h, &ev, H_SAVE, filename) == -1 ?
145415a0bb6cSchristos 	    (errno ? errno : EINVAL) : 0;
1455f7de801dSchristos }
1456f7de801dSchristos 
1457cfd23e7aSchristos int
append_history(int n,const char * filename)1458cfd23e7aSchristos append_history(int n, const char *filename)
1459cfd23e7aSchristos {
1460cfd23e7aSchristos 	HistEvent ev;
1461cfd23e7aSchristos 	FILE *fp;
1462cfd23e7aSchristos 
1463cfd23e7aSchristos 	if (h == NULL || e == NULL)
1464cfd23e7aSchristos 		rl_initialize();
1465cfd23e7aSchristos 	if (filename == NULL && (filename = _default_history_file()) == NULL)
1466cfd23e7aSchristos 		return errno;
1467cfd23e7aSchristos 
1468cfd23e7aSchristos 	if ((fp = fopen(filename, "a")) == NULL)
1469cfd23e7aSchristos 		return errno;
1470cfd23e7aSchristos 
1471cfd23e7aSchristos 	if (history(h, &ev, H_NSAVE_FP, (size_t)n,  fp) == -1) {
1472cfd23e7aSchristos 		int serrno = errno ? errno : EINVAL;
1473cfd23e7aSchristos 		fclose(fp);
1474cfd23e7aSchristos 		return serrno;
1475cfd23e7aSchristos 	}
1476cfd23e7aSchristos 	fclose(fp);
1477cfd23e7aSchristos 	return 0;
1478cfd23e7aSchristos }
1479d30d584aSlukem 
1480f7de801dSchristos /*
1481f7de801dSchristos  * returns history ``num''th event
1482f7de801dSchristos  *
1483f7de801dSchristos  * returned pointer points to static variable
1484f7de801dSchristos  */
1485bc7956deSchristos HIST_ENTRY *
history_get(int num)1486d30d584aSlukem history_get(int num)
1487f7de801dSchristos {
1488f7de801dSchristos 	static HIST_ENTRY she;
1489b3543150Schristos 	HistEvent ev;
14908b40dcaeSchristos 	int curr_num;
1491f7de801dSchristos 
1492f7de801dSchristos 	if (h == NULL || e == NULL)
1493f7de801dSchristos 		rl_initialize();
1494f7de801dSchristos 
14957e99177dSchristos 	if (num < history_base)
14967e99177dSchristos 		return NULL;
14977e99177dSchristos 
14988b40dcaeSchristos 	/* save current position */
1499b3543150Schristos 	if (history(h, &ev, H_CURR) != 0)
150015a0bb6cSchristos 		return NULL;
1501f7de801dSchristos 	curr_num = ev.num;
15028b40dcaeSchristos 
15037e99177dSchristos 	/*
15047e99177dSchristos 	 * use H_DELDATA to set to nth history (without delete) by passing
15057e99177dSchristos 	 * (void **)-1  -- as in history_set_pos
15067e99177dSchristos 	 */
15077e99177dSchristos 	if (history(h, &ev, H_DELDATA, num - history_base, (void **)-1) != 0)
15087e99177dSchristos 		goto out;
15098b40dcaeSchristos 
15107e99177dSchristos 	/* get current entry */
15117e99177dSchristos 	if (history(h, &ev, H_CURR) != 0)
15127e99177dSchristos 		goto out;
15137e99177dSchristos 	if (history(h, &ev, H_NEXT_EVDATA, ev.num, &she.data) != 0)
15147e99177dSchristos 		goto out;
1515b3543150Schristos 	she.line = ev.str;
1516f7de801dSchristos 
15178b40dcaeSchristos 	/* restore pointer to where it was */
1518b3543150Schristos 	(void)history(h, &ev, H_SET, curr_num);
1519f7de801dSchristos 
152015a0bb6cSchristos 	return &she;
15217e99177dSchristos 
15227e99177dSchristos out:
15237e99177dSchristos 	/* restore pointer to where it was */
15247e99177dSchristos 	(void)history(h, &ev, H_SET, curr_num);
15257e99177dSchristos 	return NULL;
1526f7de801dSchristos }
1527f7de801dSchristos 
1528d30d584aSlukem 
1529f7de801dSchristos /*
1530f7de801dSchristos  * add the line to history table
1531f7de801dSchristos  */
1532f7de801dSchristos int
add_history(const char * line)1533d30d584aSlukem add_history(const char *line)
1534f7de801dSchristos {
1535b3543150Schristos 	HistEvent ev;
1536f7de801dSchristos 
1537f7de801dSchristos 	if (h == NULL || e == NULL)
1538f7de801dSchristos 		rl_initialize();
1539f7de801dSchristos 
1540e0349677Schristos 	if (history(h, &ev, H_ENTER, line) == -1)
1541e0349677Schristos 		return 0;
1542e0349677Schristos 
1543e0349677Schristos 	(void)history(h, &ev, H_GETSIZE);
1544e0349677Schristos 	if (ev.num == history_length)
1545e0349677Schristos 		history_base++;
1546a5ee7703Schristos 	else {
1547a5ee7703Schristos 		history_offset++;
1548f7de801dSchristos 		history_length = ev.num;
1549a5ee7703Schristos 	}
1550e0349677Schristos 	return 0;
1551f7de801dSchristos }
1552f7de801dSchristos 
1553d30d584aSlukem 
1554f7de801dSchristos /*
155545542456Schristos  * remove the specified entry from the history list and return it.
155645542456Schristos  */
155745542456Schristos HIST_ENTRY *
remove_history(int num)155845542456Schristos remove_history(int num)
155945542456Schristos {
1560ea3813edSchristos 	HIST_ENTRY *he;
1561b3543150Schristos 	HistEvent ev;
156245542456Schristos 
156345542456Schristos 	if (h == NULL || e == NULL)
156445542456Schristos 		rl_initialize();
156545542456Schristos 
1566b95ed37eSchristos 	if ((he = el_malloc(sizeof(*he))) == NULL)
156745542456Schristos 		return NULL;
156845542456Schristos 
1569b3543150Schristos 	if (history(h, &ev, H_DELDATA, num, &he->data) != 0) {
1570b95ed37eSchristos 		el_free(he);
15712d9dad6fSchristos 		return NULL;
157245542456Schristos 	}
157345542456Schristos 
1574b3543150Schristos 	he->line = ev.str;
1575b3543150Schristos 	if (history(h, &ev, H_GETSIZE) == 0)
1576ea3813edSchristos 		history_length = ev.num;
1577ea3813edSchristos 
1578ea3813edSchristos 	return he;
1579ea3813edSchristos }
1580ea3813edSchristos 
1581ea3813edSchristos 
1582ea3813edSchristos /*
1583ea3813edSchristos  * replace the line and data of the num-th entry
1584ea3813edSchristos  */
1585ea3813edSchristos HIST_ENTRY *
replace_history_entry(int num,const char * line,histdata_t data)1586ea3813edSchristos replace_history_entry(int num, const char *line, histdata_t data)
1587ea3813edSchristos {
1588ea3813edSchristos 	HIST_ENTRY *he;
1589b3543150Schristos 	HistEvent ev;
1590ea3813edSchristos 	int curr_num;
1591ea3813edSchristos 
1592ea3813edSchristos 	if (h == NULL || e == NULL)
1593ea3813edSchristos 		rl_initialize();
1594ea3813edSchristos 
1595ea3813edSchristos 	/* save current position */
1596b3543150Schristos 	if (history(h, &ev, H_CURR) != 0)
1597ea3813edSchristos 		return NULL;
1598ea3813edSchristos 	curr_num = ev.num;
1599ea3813edSchristos 
1600ea3813edSchristos 	/* start from the oldest */
1601b3543150Schristos 	if (history(h, &ev, H_LAST) != 0)
1602ea3813edSchristos 		return NULL;	/* error */
1603ea3813edSchristos 
1604b95ed37eSchristos 	if ((he = el_malloc(sizeof(*he))) == NULL)
1605ea3813edSchristos 		return NULL;
1606ea3813edSchristos 
1607ea3813edSchristos 	/* look forwards for event matching specified offset */
1608b3543150Schristos 	if (history(h, &ev, H_NEXT_EVDATA, num, &he->data))
1609ea3813edSchristos 		goto out;
1610ea3813edSchristos 
1611a76f6146Schristos 	he->line = ev.str;
1612ea3813edSchristos 	if (he->line == NULL)
1613ea3813edSchristos 		goto out;
1614ea3813edSchristos 
1615b3543150Schristos 	if (history(h, &ev, H_REPLACE, line, data))
1616ea3813edSchristos 		goto out;
1617ea3813edSchristos 
1618ea3813edSchristos 	/* restore pointer to where it was */
1619b3543150Schristos 	if (history(h, &ev, H_SET, curr_num))
1620ea3813edSchristos 		goto out;
1621ea3813edSchristos 
1622ea3813edSchristos 	return he;
1623ea3813edSchristos out:
1624b95ed37eSchristos 	el_free(he);
1625ea3813edSchristos 	return NULL;
1626ea3813edSchristos }
162745542456Schristos 
162845542456Schristos /*
1629f7de801dSchristos  * clear the history list - delete all entries
1630f7de801dSchristos  */
1631f7de801dSchristos void
clear_history(void)1632d30d584aSlukem clear_history(void)
1633f7de801dSchristos {
1634b3543150Schristos 	HistEvent ev;
1635d30d584aSlukem 
1636dcc6b593Schristos 	if (h == NULL || e == NULL)
1637dcc6b593Schristos 		rl_initialize();
1638dcc6b593Schristos 
1639b3543150Schristos 	(void)history(h, &ev, H_CLEAR);
1640357ec4e8Schristos 	history_offset = history_length = 0;
1641f7de801dSchristos }
1642f7de801dSchristos 
1643d30d584aSlukem 
1644f7de801dSchristos /*
1645f7de801dSchristos  * returns offset of the current history event
1646f7de801dSchristos  */
1647f7de801dSchristos int
where_history(void)1648d30d584aSlukem where_history(void)
1649f7de801dSchristos {
1650357ec4e8Schristos 	return history_offset;
1651f7de801dSchristos }
1652f7de801dSchristos 
1653357ec4e8Schristos static HIST_ENTRY **_history_listp;
1654357ec4e8Schristos static HIST_ENTRY *_history_list;
1655357ec4e8Schristos 
1656357ec4e8Schristos HIST_ENTRY **
history_list(void)1657357ec4e8Schristos history_list(void)
1658357ec4e8Schristos {
1659357ec4e8Schristos 	HistEvent ev;
1660357ec4e8Schristos 	HIST_ENTRY **nlp, *nl;
1661357ec4e8Schristos 	int i;
1662357ec4e8Schristos 
1663357ec4e8Schristos 	if (history(h, &ev, H_LAST) != 0)
1664357ec4e8Schristos 		return NULL;
1665357ec4e8Schristos 
1666357ec4e8Schristos 	if ((nlp = el_realloc(_history_listp,
166703cb7836Schristos 	    ((size_t)history_length + 1) * sizeof(*nlp))) == NULL)
1668357ec4e8Schristos 		return NULL;
1669357ec4e8Schristos 	_history_listp = nlp;
1670357ec4e8Schristos 
1671357ec4e8Schristos 	if ((nl = el_realloc(_history_list,
1672357ec4e8Schristos 	    (size_t)history_length * sizeof(*nl))) == NULL)
1673357ec4e8Schristos 		return NULL;
1674357ec4e8Schristos 	_history_list = nl;
1675357ec4e8Schristos 
1676357ec4e8Schristos 	i = 0;
1677357ec4e8Schristos 	do {
1678357ec4e8Schristos 		_history_listp[i] = &_history_list[i];
1679357ec4e8Schristos 		_history_list[i].line = ev.str;
1680357ec4e8Schristos 		_history_list[i].data = NULL;
1681357ec4e8Schristos 		if (i++ == history_length)
1682357ec4e8Schristos 			abort();
1683357ec4e8Schristos 	} while (history(h, &ev, H_PREV) == 0);
168403cb7836Schristos 	_history_listp[i] = NULL;
1685357ec4e8Schristos 	return _history_listp;
1686357ec4e8Schristos }
1687d30d584aSlukem 
1688f7de801dSchristos /*
1689f7de801dSchristos  * returns current history event or NULL if there is no such event
1690f7de801dSchristos  */
1691bc7956deSchristos HIST_ENTRY *
current_history(void)1692d30d584aSlukem current_history(void)
1693f7de801dSchristos {
1694357ec4e8Schristos 	HistEvent ev;
1695d30d584aSlukem 
1696357ec4e8Schristos 	if (history(h, &ev, H_PREV_EVENT, history_offset + 1) != 0)
1697357ec4e8Schristos 		return NULL;
1698357ec4e8Schristos 
1699357ec4e8Schristos 	rl_he.line = ev.str;
1700357ec4e8Schristos 	rl_he.data = NULL;
1701357ec4e8Schristos 	return &rl_he;
1702f7de801dSchristos }
1703f7de801dSchristos 
1704d30d584aSlukem 
1705f7de801dSchristos /*
1706f7de801dSchristos  * returns total number of bytes history events' data are using
1707f7de801dSchristos  */
1708f7de801dSchristos int
history_total_bytes(void)1709d30d584aSlukem history_total_bytes(void)
1710f7de801dSchristos {
1711b3543150Schristos 	HistEvent ev;
17125c894153Schristos 	int curr_num;
17135c894153Schristos 	size_t size;
1714f7de801dSchristos 
1715b3543150Schristos 	if (history(h, &ev, H_CURR) != 0)
171615a0bb6cSchristos 		return -1;
1717f7de801dSchristos 	curr_num = ev.num;
1718f7de801dSchristos 
1719b3543150Schristos 	(void)history(h, &ev, H_FIRST);
1720f7de801dSchristos 	size = 0;
1721f7de801dSchristos 	do
1722b3543150Schristos 		size += strlen(ev.str) * sizeof(*ev.str);
1723b3543150Schristos 	while (history(h, &ev, H_NEXT) == 0);
1724f7de801dSchristos 
1725f7de801dSchristos 	/* get to the same position as before */
1726b3543150Schristos 	history(h, &ev, H_PREV_EVENT, curr_num);
1727f7de801dSchristos 
172815a0bb6cSchristos 	return (int)size;
1729f7de801dSchristos }
1730f7de801dSchristos 
1731d30d584aSlukem 
1732f7de801dSchristos /*
1733f7de801dSchristos  * sets the position in the history list to ``pos''
1734f7de801dSchristos  */
1735f7de801dSchristos int
history_set_pos(int pos)1736d30d584aSlukem history_set_pos(int pos)
1737f7de801dSchristos {
1738ea3813edSchristos 	if (pos >= history_length || pos < 0)
173915d631ccSchristos 		return 0;
1740f7de801dSchristos 
1741357ec4e8Schristos 	history_offset = pos;
174215d631ccSchristos 	return 1;
174315d631ccSchristos }
1744f7de801dSchristos 
1745d30d584aSlukem 
1746f7de801dSchristos /*
1747f7de801dSchristos  * returns previous event in history and shifts pointer accordingly
1748673b05f0Schristos  * Note that readline and editline define directions in opposite ways.
1749f7de801dSchristos  */
1750bc7956deSchristos HIST_ENTRY *
previous_history(void)1751d30d584aSlukem previous_history(void)
1752f7de801dSchristos {
1753357ec4e8Schristos 	HistEvent ev;
1754d30d584aSlukem 
1755357ec4e8Schristos 	if (history_offset == 0)
1756357ec4e8Schristos 		return NULL;
1757357ec4e8Schristos 
1758357ec4e8Schristos 	if (history(h, &ev, H_LAST) != 0)
1759357ec4e8Schristos 		return NULL;
1760357ec4e8Schristos 
1761357ec4e8Schristos 	history_offset--;
1762357ec4e8Schristos 	return current_history();
1763f7de801dSchristos }
1764f7de801dSchristos 
1765d30d584aSlukem 
1766f7de801dSchristos /*
1767f7de801dSchristos  * returns next event in history and shifts pointer accordingly
1768f7de801dSchristos  */
1769bc7956deSchristos HIST_ENTRY *
next_history(void)1770d30d584aSlukem next_history(void)
1771f7de801dSchristos {
1772357ec4e8Schristos 	HistEvent ev;
1773d30d584aSlukem 
1774357ec4e8Schristos 	if (history_offset >= history_length)
1775357ec4e8Schristos 		return NULL;
1776357ec4e8Schristos 
1777357ec4e8Schristos 	if (history(h, &ev, H_LAST) != 0)
1778357ec4e8Schristos 		return NULL;
1779357ec4e8Schristos 
1780357ec4e8Schristos 	history_offset++;
1781357ec4e8Schristos 	return current_history();
1782f7de801dSchristos }
1783f7de801dSchristos 
1784d30d584aSlukem 
1785f7de801dSchristos /*
17868b40dcaeSchristos  * searches for first history event containing the str
1787f7de801dSchristos  */
17888b40dcaeSchristos int
history_search(const char * str,int direction)17898b40dcaeSchristos history_search(const char *str, int direction)
1790f7de801dSchristos {
1791b3543150Schristos 	HistEvent ev;
1792b3543150Schristos 	const char *strp;
1793f7de801dSchristos 	int curr_num;
1794f7de801dSchristos 
1795b3543150Schristos 	if (history(h, &ev, H_CURR) != 0)
179615a0bb6cSchristos 		return -1;
1797f7de801dSchristos 	curr_num = ev.num;
1798f7de801dSchristos 
1799f7de801dSchristos 	for (;;) {
1800b3543150Schristos 		if ((strp = strstr(ev.str, str)) != NULL)
1801f7de801dSchristos 			return (int)(strp - ev.str);
1802b3543150Schristos 		if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0)
1803f7de801dSchristos 			break;
1804f7de801dSchristos 	}
1805b3543150Schristos 	(void)history(h, &ev, H_SET, curr_num);
180615a0bb6cSchristos 	return -1;
1807f7de801dSchristos }
1808f7de801dSchristos 
1809d30d584aSlukem 
1810f7de801dSchristos /*
1811f7de801dSchristos  * searches for first history event beginning with str
1812f7de801dSchristos  */
1813f7de801dSchristos int
history_search_prefix(const char * str,int direction)1814d30d584aSlukem history_search_prefix(const char *str, int direction)
1815f7de801dSchristos {
1816b3543150Schristos 	HistEvent ev;
1817d30d584aSlukem 
1818b3543150Schristos 	return (history(h, &ev, direction < 0 ?
181973eda9feSchristos 	    H_PREV_STR : H_NEXT_STR, str));
1820f7de801dSchristos }
1821f7de801dSchristos 
1822d30d584aSlukem 
1823f7de801dSchristos /*
1824f7de801dSchristos  * search for event in history containing str, starting at offset
1825f7de801dSchristos  * abs(pos); continue backward, if pos<0, forward otherwise
1826f7de801dSchristos  */
1827a0be074dSchristos /* ARGSUSED */
1828f7de801dSchristos int
history_search_pos(const char * str,int direction,int pos)1829839ca00bSchristos history_search_pos(const char *str,
1830839ca00bSchristos 		   int direction __attribute__((__unused__)), int pos)
1831f7de801dSchristos {
1832b3543150Schristos 	HistEvent ev;
1833f7de801dSchristos 	int curr_num, off;
1834f7de801dSchristos 
1835f7de801dSchristos 	off = (pos > 0) ? pos : -pos;
1836f7de801dSchristos 	pos = (pos > 0) ? 1 : -1;
1837f7de801dSchristos 
1838b3543150Schristos 	if (history(h, &ev, H_CURR) != 0)
183915a0bb6cSchristos 		return -1;
1840f7de801dSchristos 	curr_num = ev.num;
1841f7de801dSchristos 
184215d631ccSchristos 	if (!history_set_pos(off) || history(h, &ev, H_CURR) != 0)
184315a0bb6cSchristos 		return -1;
1844f7de801dSchristos 
1845f7de801dSchristos 	for (;;) {
1846b3543150Schristos 		if (strstr(ev.str, str))
184715a0bb6cSchristos 			return off;
1848b3543150Schristos 		if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0)
1849f7de801dSchristos 			break;
1850f7de801dSchristos 	}
1851f7de801dSchristos 
1852f7de801dSchristos 	/* set "current" pointer back to previous state */
1853b3543150Schristos 	(void)history(h, &ev,
185473eda9feSchristos 	    pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
1855f7de801dSchristos 
185615a0bb6cSchristos 	return -1;
1857f7de801dSchristos }
1858f7de801dSchristos 
1859f7de801dSchristos 
1860f7de801dSchristos /********************************/
1861552716dcSchristos /* completion functions */
1862f7de801dSchristos 
186319c38590Schristos char *
tilde_expand(char * name)186419c38590Schristos tilde_expand(char *name)
186519c38590Schristos {
186619c38590Schristos 	return fn_tilde_expand(name);
186719c38590Schristos }
186819c38590Schristos 
186919c38590Schristos char *
filename_completion_function(const char * name,int state)187019c38590Schristos filename_completion_function(const char *name, int state)
187119c38590Schristos {
187219c38590Schristos 	return fn_filename_completion_function(name, state);
187319c38590Schristos }
187419c38590Schristos 
1875f7de801dSchristos /*
1876f7de801dSchristos  * a completion generator for usernames; returns _first_ username
1877f7de801dSchristos  * which starts with supplied text
1878f7de801dSchristos  * text contains a partial username preceded by random character
1879cde2edd5Schristos  * (usually '~'); state resets search from start (??? should we do that anyway)
18807d1220acSsnj  * it's the caller's responsibility to free the returned value
1881f7de801dSchristos  */
1882f7de801dSchristos char *
username_completion_function(const char * text,int state)1883d30d584aSlukem username_completion_function(const char *text, int state)
1884f7de801dSchristos {
1885cde2edd5Schristos #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT)
1886cde2edd5Schristos 	struct passwd pwres;
1887bf7832efSchristos 	char pwbuf[1024];
1888cde2edd5Schristos #endif
1889cde2edd5Schristos 	struct passwd *pass = NULL;
1890f7de801dSchristos 
1891f7de801dSchristos 	if (text[0] == '\0')
189215a0bb6cSchristos 		return NULL;
1893f7de801dSchristos 
1894f7de801dSchristos 	if (*text == '~')
1895f7de801dSchristos 		text++;
1896f7de801dSchristos 
1897f7de801dSchristos 	if (state == 0)
1898f7de801dSchristos 		setpwent();
1899f7de801dSchristos 
1900cde2edd5Schristos 	while (
1901cde2edd5Schristos #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT)
1902cde2edd5Schristos 	    getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pass) == 0 && pass != NULL
1903cde2edd5Schristos #else
1904cde2edd5Schristos 	    (pass = getpwent()) != NULL
1905cde2edd5Schristos #endif
1906cde2edd5Schristos 	    && text[0] == pass->pw_name[0]
1907cde2edd5Schristos 	    && strcmp(text, pass->pw_name) == 0)
1908cde2edd5Schristos 		continue;
1909f7de801dSchristos 
1910cde2edd5Schristos 	if (pass == NULL) {
1911f7de801dSchristos 		endpwent();
1912ea3813edSchristos 		return NULL;
1913f7de801dSchristos 	}
1914cde2edd5Schristos 	return strdup(pass->pw_name);
1915f7de801dSchristos }
1916f7de801dSchristos 
1917d30d584aSlukem 
1918f7de801dSchristos /*
1919ac4e17d0Schristos  * el-compatible wrapper to send TSTP on ^Z
1920ac4e17d0Schristos  */
1921ac4e17d0Schristos /* ARGSUSED */
1922ac4e17d0Schristos static unsigned char
_el_rl_tstp(EditLine * el,int ch)1923ac4e17d0Schristos _el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__)))
1924ac4e17d0Schristos {
1925ac4e17d0Schristos 	(void)kill(0, SIGTSTP);
1926ac4e17d0Schristos 	return CC_NORM;
1927ac4e17d0Schristos }
1928d30d584aSlukem 
19293cfbfdb2Schristos static const char *
19303cfbfdb2Schristos /*ARGSUSED*/
_rl_completion_append_character_function(const char * dummy)19313cfbfdb2Schristos _rl_completion_append_character_function(const char *dummy
19323cfbfdb2Schristos     __attribute__((__unused__)))
19333cfbfdb2Schristos {
19343cfbfdb2Schristos 	static char buf[2];
1935b219d9e4Schristos 	buf[0] = (char)rl_completion_append_character;
19362d18fd40Schristos 	buf[1] = '\0';
19373cfbfdb2Schristos 	return buf;
19383cfbfdb2Schristos }
19393cfbfdb2Schristos 
1940d30d584aSlukem 
1941f7de801dSchristos /*
19424da872f8Sabhinav  * Display list of strings in columnar format on readline's output stream.
19434da872f8Sabhinav  * 'matches' is list of strings, 'len' is number of strings in 'matches',
19444da872f8Sabhinav  * 'max' is maximum length of string in 'matches'.
19454da872f8Sabhinav  */
19464da872f8Sabhinav void
rl_display_match_list(char ** matches,int len,int max)19474da872f8Sabhinav rl_display_match_list(char **matches, int len, int max)
19484da872f8Sabhinav {
19494da872f8Sabhinav 
19504da872f8Sabhinav 	fn_display_match_list(e, matches, (size_t)len, (size_t)max,
19514da872f8Sabhinav 		_rl_completion_append_character_function);
19524da872f8Sabhinav }
19534da872f8Sabhinav 
19544da872f8Sabhinav /*
1955f7de801dSchristos  * complete word at current point
1956f7de801dSchristos  */
1957af62817eSchristos /* ARGSUSED */
195841a59814Sdsl int
rl_complete(int ignore,int invoking_key)195941a59814Sdsl rl_complete(int ignore __attribute__((__unused__)), int invoking_key)
1960f7de801dSchristos {
196134e53048Schristos 	static ct_buffer_t wbreak_conv, sprefix_conv;
196208dba207Schristos 	const char *breakchars;
196334e53048Schristos 
1964f7de801dSchristos 	if (h == NULL || e == NULL)
1965f7de801dSchristos 		rl_initialize();
1966f7de801dSchristos 
1967f7de801dSchristos 	if (rl_inhibit_completion) {
19680d0ad089Schristos 		char arr[2];
19690d0ad089Schristos 		arr[0] = (char)invoking_key;
19700d0ad089Schristos 		arr[1] = '\0';
19710d0ad089Schristos 		el_insertstr(e, arr);
197215a0bb6cSchristos 		return CC_REFRESH;
1973f7de801dSchristos 	}
1974f7de801dSchristos 
197588b2cd9fSchristos 	if (rl_completion_word_break_hook != NULL)
197688b2cd9fSchristos 		breakchars = (*rl_completion_word_break_hook)();
197788b2cd9fSchristos 	else
197888b2cd9fSchristos 		breakchars = rl_basic_word_break_characters;
197988b2cd9fSchristos 
1980d64206caSchristos 	_rl_update_pos();
1981d64206caSchristos 
198241a59814Sdsl 	/* Just look at how many global variables modify this operation! */
198328b9ef37Schristos 	return fn_complete2(e,
198449603ec5Schristos 	    (rl_compentry_func_t *)rl_completion_entry_function,
198541a59814Sdsl 	    rl_attempted_completion_function,
198634e53048Schristos 	    ct_decode_string(rl_basic_word_break_characters, &wbreak_conv),
198788b2cd9fSchristos 	    ct_decode_string(breakchars, &sprefix_conv),
1988954af9bbSchristos 	    _rl_completion_append_character_function,
1989954af9bbSchristos 	    (size_t)rl_completion_query_items,
199041a59814Sdsl 	    &rl_completion_type, &rl_attempted_completion_over,
199128b9ef37Schristos 	    &rl_point, &rl_end, 0);
1992b3543150Schristos 
1993b3543150Schristos 
199441a59814Sdsl }
199541a59814Sdsl 
199641a59814Sdsl 
199741a59814Sdsl /* ARGSUSED */
199841a59814Sdsl static unsigned char
_el_rl_complete(EditLine * el,int ch)199941a59814Sdsl _el_rl_complete(EditLine *el __attribute__((__unused__)), int ch)
200041a59814Sdsl {
200141a59814Sdsl 	return (unsigned char)rl_complete(0, ch);
200241a59814Sdsl }
2003d30d584aSlukem 
2004f7de801dSchristos /*
2005f7de801dSchristos  * misc other functions
2006f7de801dSchristos  */
2007f7de801dSchristos 
2008f7de801dSchristos /*
2009f7de801dSchristos  * bind key c to readline-type function func
2010f7de801dSchristos  */
2011f7de801dSchristos int
rl_bind_key(int c,rl_command_func_t * func)2012ea3813edSchristos rl_bind_key(int c, rl_command_func_t *func)
2013f7de801dSchristos {
2014f7de801dSchristos 	int retval = -1;
2015f7de801dSchristos 
2016f7de801dSchristos 	if (h == NULL || e == NULL)
2017f7de801dSchristos 		rl_initialize();
2018f7de801dSchristos 
2019f7de801dSchristos 	if (func == rl_insert) {
2020f7de801dSchristos 		/* XXX notice there is no range checking of ``c'' */
2021f7de801dSchristos 		e->el_map.key[c] = ED_INSERT;
2022f7de801dSchristos 		retval = 0;
2023f7de801dSchristos 	}
202415a0bb6cSchristos 	return retval;
2025f7de801dSchristos }
2026f7de801dSchristos 
2027d30d584aSlukem 
2028f7de801dSchristos /*
2029f7de801dSchristos  * read one key from input - handles chars pushed back
2030f7de801dSchristos  * to input stream also
2031f7de801dSchristos  */
2032f7de801dSchristos int
rl_read_key(void)2033d30d584aSlukem rl_read_key(void)
2034f7de801dSchristos {
2035f7de801dSchristos 	char fooarr[2 * sizeof(int)];
2036f7de801dSchristos 
2037f7de801dSchristos 	if (e == NULL || h == NULL)
2038f7de801dSchristos 		rl_initialize();
2039f7de801dSchristos 
204015a0bb6cSchristos 	return el_getc(e, fooarr);
2041f7de801dSchristos }
2042f7de801dSchristos 
2043d30d584aSlukem 
2044f7de801dSchristos /*
2045f7de801dSchristos  * reset the terminal
2046f7de801dSchristos  */
2047a0be074dSchristos /* ARGSUSED */
204808dba207Schristos int
rl_reset_terminal(const char * p)2049839ca00bSchristos rl_reset_terminal(const char *p __attribute__((__unused__)))
2050f7de801dSchristos {
2051d30d584aSlukem 
2052f7de801dSchristos 	if (h == NULL || e == NULL)
2053f7de801dSchristos 		rl_initialize();
2054f7de801dSchristos 	el_reset(e);
205508dba207Schristos 	return 0;
2056f7de801dSchristos }
2057f7de801dSchristos 
2058d30d584aSlukem 
2059f7de801dSchristos /*
2060f7de801dSchristos  * insert character ``c'' back into input stream, ``count'' times
2061f7de801dSchristos  */
2062f7de801dSchristos int
rl_insert(int count,int c)2063d30d584aSlukem rl_insert(int count, int c)
2064f7de801dSchristos {
2065f7de801dSchristos 	char arr[2];
2066f7de801dSchristos 
2067f7de801dSchristos 	if (h == NULL || e == NULL)
2068f7de801dSchristos 		rl_initialize();
2069f7de801dSchristos 
2070f7de801dSchristos 	/* XXX - int -> char conversion can lose on multichars */
2071b219d9e4Schristos 	arr[0] = (char)c;
2072f7de801dSchristos 	arr[1] = '\0';
2073f7de801dSchristos 
2074f7de801dSchristos 	for (; count > 0; count--)
2075f7de801dSchristos 		el_push(e, arr);
2076f7de801dSchristos 
207715a0bb6cSchristos 	return 0;
2078f7de801dSchristos }
2079552716dcSchristos 
2080ea3813edSchristos int
rl_insert_text(const char * text)2081ea3813edSchristos rl_insert_text(const char *text)
2082ea3813edSchristos {
2083ea3813edSchristos 	if (!text || *text == 0)
208415a0bb6cSchristos 		return 0;
2085ea3813edSchristos 
2086ea3813edSchristos 	if (h == NULL || e == NULL)
2087ea3813edSchristos 		rl_initialize();
2088ea3813edSchristos 
2089ea3813edSchristos 	if (el_insertstr(e, text) < 0)
209015a0bb6cSchristos 		return 0;
2091ea3813edSchristos 	return (int)strlen(text);
2092ea3813edSchristos }
2093ea3813edSchristos 
2094552716dcSchristos /*ARGSUSED*/
2095552716dcSchristos int
rl_newline(int count,int c)20964b7bc181Schristos rl_newline(int count __attribute__((__unused__)),
20974b7bc181Schristos     int c __attribute__((__unused__)))
2098552716dcSchristos {
2099552716dcSchristos 	/*
2100552716dcSchristos 	 * Readline-4.0 appears to ignore the args.
2101552716dcSchristos 	 */
2102552716dcSchristos 	return rl_insert(1, '\n');
2103552716dcSchristos }
2104552716dcSchristos 
2105552716dcSchristos /*ARGSUSED*/
2106552716dcSchristos static unsigned char
rl_bind_wrapper(EditLine * el,unsigned char c)21074b7bc181Schristos rl_bind_wrapper(EditLine *el __attribute__((__unused__)), unsigned char c)
2108552716dcSchristos {
2109552716dcSchristos 	if (map[c] == NULL)
2110552716dcSchristos 		return CC_ERROR;
2111af62817eSchristos 
2112af62817eSchristos 	_rl_update_pos();
2113af62817eSchristos 
2114d64206caSchristos 	(*map[c])(1, c);
21155d79eff8Schristos 
21165d79eff8Schristos 	/* If rl_done was set by the above call, deal with it here */
21175d79eff8Schristos 	if (rl_done)
21185d79eff8Schristos 		return CC_EOF;
21195d79eff8Schristos 
2120552716dcSchristos 	return CC_NORM;
2121552716dcSchristos }
2122552716dcSchristos 
2123552716dcSchristos int
rl_add_defun(const char * name,rl_command_func_t * fun,int c)2124d64206caSchristos rl_add_defun(const char *name, rl_command_func_t *fun, int c)
2125552716dcSchristos {
2126552716dcSchristos 	char dest[8];
2127a06595c2Slukem 	if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0)
2128552716dcSchristos 		return -1;
2129552716dcSchristos 	map[(unsigned char)c] = fun;
2130552716dcSchristos 	el_set(e, EL_ADDFN, name, name, rl_bind_wrapper);
2131378865a4Schristos 	vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0);
213281c77988Schristos 	el_set(e, EL_BIND, dest, name, NULL);
2133552716dcSchristos 	return 0;
2134552716dcSchristos }
2135552716dcSchristos 
2136552716dcSchristos void
rl_callback_read_char(void)21378c1dba6cSmatt rl_callback_read_char(void)
2138552716dcSchristos {
21395eda4a7dSchristos 	int count = 0, done = 0;
2140552716dcSchristos 	const char *buf = el_gets(e, &count);
2141552716dcSchristos 	char *wbuf;
2142552716dcSchristos 
214332c5df9eSchristos 	el_set(e, EL_UNBUFFERED, 1);
2144552716dcSchristos 	if (buf == NULL || count-- <= 0)
2145552716dcSchristos 		return;
21460fd1bd62Schristos 	if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF])
21475eda4a7dSchristos 		done = 1;
21485eda4a7dSchristos 	if (buf[count] == '\n' || buf[count] == '\r')
21495eda4a7dSchristos 		done = 2;
21505eda4a7dSchristos 
21515eda4a7dSchristos 	if (done && rl_linefunc != NULL) {
2152552716dcSchristos 		el_set(e, EL_UNBUFFERED, 0);
21535eda4a7dSchristos 		if (done == 2) {
2154552716dcSchristos 			if ((wbuf = strdup(buf)) != NULL)
2155552716dcSchristos 				wbuf[count] = '\0';
21562feacb00Schristos 			RL_SETSTATE(RL_STATE_DONE);
21575eda4a7dSchristos 		} else
21585eda4a7dSchristos 			wbuf = NULL;
2159552716dcSchristos 		(*(void (*)(const char *))rl_linefunc)(wbuf);
2160552716dcSchristos 	}
2161965097e3Schristos 	_rl_update_pos();
2162552716dcSchristos }
2163552716dcSchristos 
2164552716dcSchristos void
rl_callback_handler_install(const char * prompt,rl_vcpfunc_t * linefunc)216549603ec5Schristos rl_callback_handler_install(const char *prompt, rl_vcpfunc_t *linefunc)
2166552716dcSchristos {
2167552716dcSchristos 	if (e == NULL) {
2168552716dcSchristos 		rl_initialize();
2169552716dcSchristos 	}
2170d052ee7bSchristos 	(void)rl_set_prompt(prompt);
2171552716dcSchristos 	rl_linefunc = linefunc;
2172552716dcSchristos 	el_set(e, EL_UNBUFFERED, 1);
2173552716dcSchristos }
2174552716dcSchristos 
2175552716dcSchristos void
rl_callback_handler_remove(void)2176552716dcSchristos rl_callback_handler_remove(void)
2177552716dcSchristos {
217832c5df9eSchristos 	el_set(e, EL_UNBUFFERED, 0);
21795f3802caSchristos 	rl_linefunc = NULL;
2180552716dcSchristos }
2181552716dcSchristos 
2182552716dcSchristos void
rl_redisplay(void)2183552716dcSchristos rl_redisplay(void)
2184552716dcSchristos {
2185552716dcSchristos 	char a[2];
2186b219d9e4Schristos 	a[0] = (char)e->el_tty.t_c[TS_IO][C_REPRINT];
2187552716dcSchristos 	a[1] = '\0';
2188552716dcSchristos 	el_push(e, a);
2189965097e3Schristos 	rl_forced_update_display();
2190552716dcSchristos }
2191552716dcSchristos 
2192552716dcSchristos int
rl_get_previous_history(int count,int key)2193552716dcSchristos rl_get_previous_history(int count, int key)
2194552716dcSchristos {
2195552716dcSchristos 	char a[2];
2196b219d9e4Schristos 	a[0] = (char)key;
2197552716dcSchristos 	a[1] = '\0';
2198552716dcSchristos 	while (count--)
2199552716dcSchristos 		el_push(e, a);
2200552716dcSchristos 	return 0;
2201552716dcSchristos }
22025d79eff8Schristos 
22035d79eff8Schristos void
22045d79eff8Schristos /*ARGSUSED*/
rl_prep_terminal(int meta_flag)22054b7bc181Schristos rl_prep_terminal(int meta_flag __attribute__((__unused__)))
22065d79eff8Schristos {
22075d79eff8Schristos 	el_set(e, EL_PREP_TERM, 1);
22085d79eff8Schristos }
22095d79eff8Schristos 
22105d79eff8Schristos void
rl_deprep_terminal(void)2211213f1e24Schristos rl_deprep_terminal(void)
22125d79eff8Schristos {
22135d79eff8Schristos 	el_set(e, EL_PREP_TERM, 0);
22145d79eff8Schristos }
22155d79eff8Schristos 
22165d79eff8Schristos int
rl_read_init_file(const char * s)22175d79eff8Schristos rl_read_init_file(const char *s)
22185d79eff8Schristos {
221915a0bb6cSchristos 	return el_source(e, s);
22205d79eff8Schristos }
22215d79eff8Schristos 
22225d79eff8Schristos int
rl_parse_and_bind(const char * line)22235d79eff8Schristos rl_parse_and_bind(const char *line)
22245d79eff8Schristos {
22255d79eff8Schristos 	const char **argv;
22265d79eff8Schristos 	int argc;
22275d79eff8Schristos 	Tokenizer *tok;
22285d79eff8Schristos 
22295d79eff8Schristos 	tok = tok_init(NULL);
2230a9beb0e4Slukem 	tok_str(tok, line, &argc, &argv);
22315d79eff8Schristos 	argc = el_parse(e, argc, argv);
22325d79eff8Schristos 	tok_end(tok);
223315a0bb6cSchristos 	return argc ? 1 : 0;
22345d79eff8Schristos }
22355d79eff8Schristos 
2236a76abbedSchristos int
rl_variable_bind(const char * var,const char * value)2237a76abbedSchristos rl_variable_bind(const char *var, const char *value)
2238a76abbedSchristos {
2239a76abbedSchristos 	/*
2240a76abbedSchristos 	 * The proper return value is undocument, but this is what the
2241a76abbedSchristos 	 * readline source seems to do.
2242a76abbedSchristos 	 */
224381c77988Schristos 	return el_set(e, EL_BIND, "", var, value, NULL) == -1 ? 1 : 0;
2244a76abbedSchristos }
2245a76abbedSchristos 
224608dba207Schristos int
rl_stuff_char(int c)22475d79eff8Schristos rl_stuff_char(int c)
22485d79eff8Schristos {
22495d79eff8Schristos 	char buf[2];
22505d79eff8Schristos 
2251b219d9e4Schristos 	buf[0] = (char)c;
22525d79eff8Schristos 	buf[1] = '\0';
22535d79eff8Schristos 	el_insertstr(e, buf);
225408dba207Schristos 	return 1;
22555d79eff8Schristos }
22565d79eff8Schristos 
22575d79eff8Schristos static int
_rl_event_read_char(EditLine * el,wchar_t * wc)2258a7b81d12Schristos _rl_event_read_char(EditLine *el, wchar_t *wc)
22595d79eff8Schristos {
2260a7b81d12Schristos 	char	ch;
22615c894153Schristos 	int	n;
22625c894153Schristos 	ssize_t num_read = 0;
22635d79eff8Schristos 
2264a7b81d12Schristos 	ch = '\0';
2265a7b81d12Schristos 	*wc = L'\0';
22665d79eff8Schristos 	while (rl_event_hook) {
22675d79eff8Schristos 
22685d79eff8Schristos 		(*rl_event_hook)();
22695d79eff8Schristos 
22705d79eff8Schristos #if defined(FIONREAD)
22715d79eff8Schristos 		if (ioctl(el->el_infd, FIONREAD, &n) < 0)
227215a0bb6cSchristos 			return -1;
22735d79eff8Schristos 		if (n)
2274a7b81d12Schristos 			num_read = read(el->el_infd, &ch, (size_t)1);
22755d79eff8Schristos 		else
22765d79eff8Schristos 			num_read = 0;
22775d79eff8Schristos #elif defined(F_SETFL) && defined(O_NDELAY)
22785d79eff8Schristos 		if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0)
227915a0bb6cSchristos 			return -1;
22805d79eff8Schristos 		if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0)
228115a0bb6cSchristos 			return -1;
2282a7b81d12Schristos 		num_read = read(el->el_infd, &ch, 1);
22835d79eff8Schristos 		if (fcntl(el->el_infd, F_SETFL, n))
228415a0bb6cSchristos 			return -1;
22855d79eff8Schristos #else
22865d79eff8Schristos 		/* not non-blocking, but what you gonna do? */
2287a7b81d12Schristos 		num_read = read(el->el_infd, &ch, 1);
228815a0bb6cSchristos 		return -1;
22895d79eff8Schristos #endif
22905d79eff8Schristos 
22915d79eff8Schristos 		if (num_read < 0 && errno == EAGAIN)
22925d79eff8Schristos 			continue;
22935d79eff8Schristos 		if (num_read == 0)
22945d79eff8Schristos 			continue;
22955d79eff8Schristos 		break;
22965d79eff8Schristos 	}
22975d79eff8Schristos 	if (!rl_event_hook)
22985d79eff8Schristos 		el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN);
2299a7b81d12Schristos 	*wc = (wchar_t)ch;
23005c894153Schristos 	return (int)num_read;
23015d79eff8Schristos }
2302af62817eSchristos 
2303af62817eSchristos static void
_rl_update_pos(void)2304af62817eSchristos _rl_update_pos(void)
2305af62817eSchristos {
2306af62817eSchristos 	const LineInfo *li = el_line(e);
2307af62817eSchristos 
23085c894153Schristos 	rl_point = (int)(li->cursor - li->buffer);
23095c894153Schristos 	rl_end = (int)(li->lastchar - li->buffer);
2310b025706dSchristos 	rl_line_buffer[rl_end] = '\0';
2311af62817eSchristos }
23126b8a7930Schristos 
23130b50653eSchristos char *
rl_copy_text(int from,int to)23140b50653eSchristos rl_copy_text(int from, int to)
23150b50653eSchristos {
2316e74b2a38Schristos 	const LineInfo *li;
23170b50653eSchristos 	size_t len;
23180b50653eSchristos 	char * out;
23190b50653eSchristos 
2320e74b2a38Schristos 	if (h == NULL || e == NULL)
2321e74b2a38Schristos 		rl_initialize();
2322e74b2a38Schristos 
2323e74b2a38Schristos 	li = el_line(e);
2324e74b2a38Schristos 
23250b50653eSchristos 	if (from > to)
23260b50653eSchristos 		return NULL;
23270b50653eSchristos 
23280b50653eSchristos 	if (li->buffer + from > li->lastchar)
23290b50653eSchristos 		from = (int)(li->lastchar - li->buffer);
23300b50653eSchristos 
23310b50653eSchristos 	if (li->buffer + to > li->lastchar)
23320b50653eSchristos 		to = (int)(li->lastchar - li->buffer);
23330b50653eSchristos 
23340b50653eSchristos 	len = (size_t)(to - from);
23350b50653eSchristos 	out = el_malloc((size_t)len + 1);
23360a0d5a75Schristos 	if (out == NULL)
23370a0d5a75Schristos 		return NULL;
23380b50653eSchristos 	(void)strlcpy(out, li->buffer + from , len);
23390b50653eSchristos 
23400b50653eSchristos 	return out;
23410b50653eSchristos }
23420b50653eSchristos 
23430b50653eSchristos void
rl_replace_line(const char * text,int clear_undo)23440b50653eSchristos rl_replace_line(const char * text, int clear_undo __attribute__((__unused__)))
23450b50653eSchristos {
23460b50653eSchristos 	if (!text || *text == 0)
23470b50653eSchristos 		return;
23480b50653eSchristos 
23490b50653eSchristos 	if (h == NULL || e == NULL)
23500b50653eSchristos 		rl_initialize();
23510b50653eSchristos 
23520b50653eSchristos 	el_replacestr(e, text);
23530b50653eSchristos }
23540b50653eSchristos 
23559fef940fSchristos int
rl_delete_text(int start,int end)23569fef940fSchristos rl_delete_text(int start, int end)
23579fef940fSchristos {
23589fef940fSchristos 
23599fef940fSchristos 	if (h == NULL || e == NULL)
23609fef940fSchristos 		rl_initialize();
23619fef940fSchristos 
23629fef940fSchristos 	return el_deletestr1(e, start, end);
23639fef940fSchristos }
23649fef940fSchristos 
23656b8a7930Schristos void
rl_get_screen_size(int * rows,int * cols)23666b8a7930Schristos rl_get_screen_size(int *rows, int *cols)
23676b8a7930Schristos {
23686b8a7930Schristos 	if (rows)
23690fb0b804Schristos 		el_get(e, EL_GETTC, "li", rows);
23706b8a7930Schristos 	if (cols)
23710fb0b804Schristos 		el_get(e, EL_GETTC, "co", cols);
23726b8a7930Schristos }
23736b8a7930Schristos 
23740b50653eSchristos #define MAX_MESSAGE 160
23750b50653eSchristos void
rl_message(const char * format,...)23760b50653eSchristos rl_message(const char *format, ...)
23770b50653eSchristos {
23780b50653eSchristos 	char msg[MAX_MESSAGE];
23790b50653eSchristos 	va_list args;
23800b50653eSchristos 
23810b50653eSchristos 	va_start(args, format);
23820b50653eSchristos 	vsnprintf(msg, sizeof(msg), format, args);
23830b50653eSchristos 	va_end(args);
23840b50653eSchristos 
23850b50653eSchristos 	rl_set_prompt(msg);
2386965097e3Schristos 	rl_forced_update_display();
23870b50653eSchristos }
23880b50653eSchristos 
23896b8a7930Schristos void
rl_set_screen_size(int rows,int cols)23906b8a7930Schristos rl_set_screen_size(int rows, int cols)
23916b8a7930Schristos {
23926b8a7930Schristos 	char buf[64];
23936b8a7930Schristos 	(void)snprintf(buf, sizeof(buf), "%d", rows);
239481c77988Schristos 	el_set(e, EL_SETTC, "li", buf, NULL);
23956b8a7930Schristos 	(void)snprintf(buf, sizeof(buf), "%d", cols);
239681c77988Schristos 	el_set(e, EL_SETTC, "co", buf, NULL);
23976b8a7930Schristos }
23986b8a7930Schristos 
23992d9dad6fSchristos char **
rl_completion_matches(const char * str,rl_compentry_func_t * fun)24002d9dad6fSchristos rl_completion_matches(const char *str, rl_compentry_func_t *fun)
24012d9dad6fSchristos {
24022d9dad6fSchristos 	size_t len, max, i, j, min;
24032d9dad6fSchristos 	char **list, *match, *a, *b;
24042d9dad6fSchristos 
24052d9dad6fSchristos 	len = 1;
24062d9dad6fSchristos 	max = 10;
24075439fdddSchristos 	if ((list = el_calloc(max, sizeof(*list))) == NULL)
24082d9dad6fSchristos 		return NULL;
24092d9dad6fSchristos 
24102d9dad6fSchristos 	while ((match = (*fun)(str, (int)(len - 1))) != NULL) {
241146db7d01Schristos 		list[len++] = match;
24122d9dad6fSchristos 		if (len == max) {
24132d9dad6fSchristos 			char **nl;
24142d9dad6fSchristos 			max += 10;
2415b95ed37eSchristos 			if ((nl = el_realloc(list, max * sizeof(*nl))) == NULL)
24162d9dad6fSchristos 				goto out;
24172d9dad6fSchristos 			list = nl;
24182d9dad6fSchristos 		}
24192d9dad6fSchristos 	}
24202d9dad6fSchristos 	if (len == 1)
24212d9dad6fSchristos 		goto out;
24222d9dad6fSchristos 	list[len] = NULL;
24232d9dad6fSchristos 	if (len == 2) {
24242d9dad6fSchristos 		if ((list[0] = strdup(list[1])) == NULL)
24252d9dad6fSchristos 			goto out;
24262d9dad6fSchristos 		return list;
24272d9dad6fSchristos 	}
24282d9dad6fSchristos 	qsort(&list[1], len - 1, sizeof(*list),
24292d9dad6fSchristos 	    (int (*)(const void *, const void *)) strcmp);
2430079ba843Schristos 	min = SIZE_MAX;
24312d9dad6fSchristos 	for (i = 1, a = list[i]; i < len - 1; i++, a = b) {
24322d9dad6fSchristos 		b = list[i + 1];
24332d9dad6fSchristos 		for (j = 0; a[j] && a[j] == b[j]; j++)
24342d9dad6fSchristos 			continue;
24352d9dad6fSchristos 		if (min > j)
24362d9dad6fSchristos 			min = j;
24372d9dad6fSchristos 	}
24382d9dad6fSchristos 	if (min == 0 && *str) {
24392d9dad6fSchristos 		if ((list[0] = strdup(str)) == NULL)
24402d9dad6fSchristos 			goto out;
24412d9dad6fSchristos 	} else {
24425439fdddSchristos 		if ((list[0] = el_calloc(min + 1, sizeof(*list[0]))) == NULL)
24432d9dad6fSchristos 			goto out;
24442d9dad6fSchristos 		(void)memcpy(list[0], list[1], min);
24452d9dad6fSchristos 		list[0][min] = '\0';
24462d9dad6fSchristos 	}
24472d9dad6fSchristos 	return list;
24482d9dad6fSchristos 
24492d9dad6fSchristos out:
2450b95ed37eSchristos 	el_free(list);
24512d9dad6fSchristos 	return NULL;
24522d9dad6fSchristos }
24532d9dad6fSchristos 
24546b8a7930Schristos char *
rl_filename_completion_function(const char * text,int state)24556b8a7930Schristos rl_filename_completion_function (const char *text, int state)
24566b8a7930Schristos {
24576b8a7930Schristos 	return fn_filename_completion_function(text, state);
24586b8a7930Schristos }
24596b8a7930Schristos 
24603bbc95f3Schristos void
rl_forced_update_display(void)24613bbc95f3Schristos rl_forced_update_display(void)
24623bbc95f3Schristos {
24630cb4d42eSchristos 	el_set(e, EL_REFRESH);
24643bbc95f3Schristos }
24653bbc95f3Schristos 
24666b8a7930Schristos int
_rl_abort_internal(void)24676b8a7930Schristos _rl_abort_internal(void)
24686b8a7930Schristos {
24696b8a7930Schristos 	el_beep(e);
24706b8a7930Schristos 	longjmp(topbuf, 1);
24716b8a7930Schristos 	/*NOTREACHED*/
24726b8a7930Schristos }
24736b8a7930Schristos 
24746b8a7930Schristos int
_rl_qsort_string_compare(char ** s1,char ** s2)24756b8a7930Schristos _rl_qsort_string_compare(char **s1, char **s2)
24766b8a7930Schristos {
24776b8a7930Schristos 	return strcoll(*s1, *s2);
24786b8a7930Schristos }
24796b8a7930Schristos 
2480ea3813edSchristos HISTORY_STATE *
history_get_history_state(void)2481ea3813edSchristos history_get_history_state(void)
2482ea3813edSchristos {
2483ea3813edSchristos 	HISTORY_STATE *hs;
2484ea3813edSchristos 
2485b95ed37eSchristos 	if ((hs = el_malloc(sizeof(*hs))) == NULL)
248615a0bb6cSchristos 		return NULL;
2487ea3813edSchristos 	hs->length = history_length;
248815a0bb6cSchristos 	return hs;
2489ea3813edSchristos }
2490ea3813edSchristos 
24916b8a7930Schristos int
24926b8a7930Schristos /*ARGSUSED*/
rl_kill_text(int from,int to)24934b7bc181Schristos rl_kill_text(int from __attribute__((__unused__)),
24944b7bc181Schristos     int to __attribute__((__unused__)))
24956b8a7930Schristos {
24966b8a7930Schristos 	return 0;
24976b8a7930Schristos }
24986b8a7930Schristos 
24996b8a7930Schristos Keymap
rl_make_bare_keymap(void)25006b8a7930Schristos rl_make_bare_keymap(void)
25016b8a7930Schristos {
25026b8a7930Schristos 	return NULL;
25036b8a7930Schristos }
25046b8a7930Schristos 
25056b8a7930Schristos Keymap
rl_get_keymap(void)25066b8a7930Schristos rl_get_keymap(void)
25076b8a7930Schristos {
25086b8a7930Schristos 	return NULL;
25096b8a7930Schristos }
25106b8a7930Schristos 
25116b8a7930Schristos void
25126b8a7930Schristos /*ARGSUSED*/
rl_set_keymap(Keymap k)25134b7bc181Schristos rl_set_keymap(Keymap k __attribute__((__unused__)))
25146b8a7930Schristos {
25156b8a7930Schristos }
25166b8a7930Schristos 
25176b8a7930Schristos int
25186b8a7930Schristos /*ARGSUSED*/
rl_generic_bind(int type,const char * keyseq,const char * data,Keymap k)25194b7bc181Schristos rl_generic_bind(int type __attribute__((__unused__)),
25204b7bc181Schristos     const char * keyseq __attribute__((__unused__)),
25214b7bc181Schristos     const char * data __attribute__((__unused__)),
25224b7bc181Schristos     Keymap k __attribute__((__unused__)))
25236b8a7930Schristos {
25246b8a7930Schristos 	return 0;
25256b8a7930Schristos }
25266b8a7930Schristos 
25276b8a7930Schristos int
25286b8a7930Schristos /*ARGSUSED*/
rl_bind_key_in_map(int key,rl_command_func_t * fun,Keymap k)25294b7bc181Schristos rl_bind_key_in_map(int key __attribute__((__unused__)),
25304b7bc181Schristos     rl_command_func_t *fun __attribute__((__unused__)),
25314b7bc181Schristos     Keymap k __attribute__((__unused__)))
25326b8a7930Schristos {
25336b8a7930Schristos 	return 0;
25346b8a7930Schristos }
2535ea3813edSchristos 
25369fef940fSchristos int
rl_set_key(const char * keyseq,rl_command_func_t * function,Keymap k)25379fef940fSchristos rl_set_key(const char *keyseq  __attribute__((__unused__)),
25389fef940fSchristos 	rl_command_func_t *function __attribute__((__unused__)),
25399fef940fSchristos 	Keymap k __attribute__((__unused__)))
25409fef940fSchristos {
25419fef940fSchristos 	return 0;
25429fef940fSchristos }
25439fef940fSchristos 
2544ea3813edSchristos /* unsupported, but needed by python */
2545ea3813edSchristos void
rl_cleanup_after_signal(void)2546ea3813edSchristos rl_cleanup_after_signal(void)
2547ea3813edSchristos {
2548ea3813edSchristos }
25496e1c968dSchristos 
25506e1c968dSchristos int
rl_on_new_line(void)25516e1c968dSchristos rl_on_new_line(void)
25526e1c968dSchristos {
25536e1c968dSchristos 	return 0;
25546e1c968dSchristos }
2555f2840181Schristos 
2556f2840181Schristos void
rl_free_line_state(void)2557f2840181Schristos rl_free_line_state(void)
2558f2840181Schristos {
2559f2840181Schristos }
256005a7e9c3Schristos 
256105a7e9c3Schristos int
256205a7e9c3Schristos /*ARGSUSED*/
rl_set_keyboard_input_timeout(int u)2563130c73caSchristos rl_set_keyboard_input_timeout(int u __attribute__((__unused__)))
256405a7e9c3Schristos {
256505a7e9c3Schristos 	return 0;
256605a7e9c3Schristos }
2567cfd23e7aSchristos 
2568cfd23e7aSchristos void
rl_resize_terminal(void)2569cfd23e7aSchristos rl_resize_terminal(void)
2570cfd23e7aSchristos {
2571cfd23e7aSchristos 	el_resize(e);
2572cfd23e7aSchristos }
25739ab7a43bSchristos 
25749ab7a43bSchristos void
rl_reset_after_signal(void)25759ab7a43bSchristos rl_reset_after_signal(void)
25769ab7a43bSchristos {
25779ab7a43bSchristos 	if (rl_prep_term_function)
25789debc6b7Schristos 		(*rl_prep_term_function)(1);
25799ab7a43bSchristos }
25809ab7a43bSchristos 
25819ab7a43bSchristos void
rl_echo_signal_char(int sig)25829ab7a43bSchristos rl_echo_signal_char(int sig)
25839ab7a43bSchristos {
25849ab7a43bSchristos 	int c = tty_get_signal_character(e, sig);
25859ab7a43bSchristos 	if (c == -1)
25869ab7a43bSchristos 		return;
25879ab7a43bSchristos 	re_putc(e, c, 0);
25889ab7a43bSchristos }
25890d6bfd89Schristos 
25900d6bfd89Schristos int
rl_crlf(void)25910d6bfd89Schristos rl_crlf(void)
25920d6bfd89Schristos {
25930d6bfd89Schristos 	re_putc(e, '\n', 0);
25940d6bfd89Schristos 	return 0;
25950d6bfd89Schristos }
25960d6bfd89Schristos 
25970d6bfd89Schristos int
rl_ding(void)25980d6bfd89Schristos rl_ding(void)
25990d6bfd89Schristos {
26000d6bfd89Schristos 	re_putc(e, '\a', 0);
26010d6bfd89Schristos 	return 0;
26020d6bfd89Schristos }
26030d6bfd89Schristos 
26040d6bfd89Schristos int
rl_abort(int count,int key)26050d6bfd89Schristos rl_abort(int count, int key)
26060d6bfd89Schristos {
26070d6bfd89Schristos 	return count && key ? 0 : 0;
26080d6bfd89Schristos }
26090d6bfd89Schristos 
26100d6bfd89Schristos int
rl_set_keymap_name(const char * name,Keymap k)26110d6bfd89Schristos rl_set_keymap_name(const char *name, Keymap k)
26120d6bfd89Schristos {
26130d6bfd89Schristos 	return name && k ? 0 : 0;
26140d6bfd89Schristos }
26150d6bfd89Schristos 
26160d6bfd89Schristos histdata_t
free_history_entry(HIST_ENTRY * he)26170d6bfd89Schristos free_history_entry(HIST_ENTRY *he)
26180d6bfd89Schristos {
26190d6bfd89Schristos 	return he ? NULL : NULL;
26200d6bfd89Schristos }
26210d6bfd89Schristos 
26220d6bfd89Schristos void
_rl_erase_entire_line(void)26230d6bfd89Schristos _rl_erase_entire_line(void)
26240d6bfd89Schristos {
26250d6bfd89Schristos }
2626