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