1220329Sobrien/*	$NetBSD: readline.c,v 1.90 2010/08/04 20:29:18 christos Exp $	*/
2220176Sobrien
3220176Sobrien/*-
4220176Sobrien * Copyright (c) 1997 The NetBSD Foundation, Inc.
5220176Sobrien * All rights reserved.
6220176Sobrien *
7220176Sobrien * This code is derived from software contributed to The NetBSD Foundation
8220176Sobrien * by Jaromir Dolecek.
9220176Sobrien *
10220176Sobrien * Redistribution and use in source and binary forms, with or without
11220176Sobrien * modification, are permitted provided that the following conditions
12220176Sobrien * are met:
13220176Sobrien * 1. Redistributions of source code must retain the above copyright
14220176Sobrien *    notice, this list of conditions and the following disclaimer.
15220176Sobrien * 2. Redistributions in binary form must reproduce the above copyright
16220176Sobrien *    notice, this list of conditions and the following disclaimer in the
17220176Sobrien *    documentation and/or other materials provided with the distribution.
18220176Sobrien *
19220176Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20220176Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21220176Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22220176Sobrien * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23220176Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24220176Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25220176Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26220176Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27220176Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28220176Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29220176Sobrien * POSSIBILITY OF SUCH DAMAGE.
30220176Sobrien */
31220176Sobrien
32220370Sobrien#include <sys/cdefs.h>
33220329Sobrien__RCSID("$NetBSD: readline.c,v 1.90 2010/08/04 20:29:18 christos Exp $");
34220370Sobrien__FBSDID("$FreeBSD$");
35220176Sobrien
36220176Sobrien#include <sys/types.h>
37220176Sobrien#include <sys/stat.h>
38220176Sobrien#include <stdio.h>
39220176Sobrien#include <dirent.h>
40220176Sobrien#include <string.h>
41220176Sobrien#include <pwd.h>
42220176Sobrien#include <ctype.h>
43220176Sobrien#include <stdlib.h>
44220176Sobrien#include <unistd.h>
45220176Sobrien#include <limits.h>
46220178Sobrien#include <errno.h>
47220178Sobrien#include <fcntl.h>
48220218Sobrien#include <setjmp.h>
49220178Sobrien#include <vis.h>
50220370Sobrien#include "sys.h"
51220220Sobrien#include "readline/readline.h"
52220370Sobrien#include "chartype.h"
53220178Sobrien#include "el.h"
54220178Sobrien#include "fcns.h"		/* for EL_NUM_FCNS */
55220176Sobrien#include "histedit.h"
56220178Sobrien#include "filecomplete.h"
57220176Sobrien
58220218Sobrienvoid rl_prep_terminal(int);
59220218Sobrienvoid rl_deprep_terminal(void);
60220218Sobrien
61220176Sobrien/* for rl_complete() */
62220178Sobrien#define TAB		'\r'
63220176Sobrien
64220176Sobrien/* see comment at the #ifdef for sense of this */
65220178Sobrien/* #define GDB_411_HACK */
66220176Sobrien
67220176Sobrien/* readline compatibility stuff - look at readline sources/documentation */
68220176Sobrien/* to see what these variables mean */
69220176Sobrienconst char *rl_library_version = "EditLine wrapper";
70220220Sobrienint rl_readline_version = RL_READLINE_VERSION;
71220178Sobrienstatic char empty[] = { '\0' };
72220178Sobrienstatic char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' };
73220178Sobrienstatic char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$',
74220178Sobrien    '>', '<', '=', ';', '|', '&', '{', '(', '\0' };
75220178Sobrienchar *rl_readline_name = empty;
76220176SobrienFILE *rl_instream = NULL;
77220176SobrienFILE *rl_outstream = NULL;
78220176Sobrienint rl_point = 0;
79220176Sobrienint rl_end = 0;
80220176Sobrienchar *rl_line_buffer = NULL;
81220178SobrienVCPFunction *rl_linefunc = NULL;
82220178Sobrienint rl_done = 0;
83220178SobrienVFunction *rl_event_hook = NULL;
84220218SobrienKEYMAP_ENTRY_ARRAY emacs_standard_keymap,
85220218Sobrien    emacs_meta_keymap,
86220218Sobrien    emacs_ctlx_keymap;
87220176Sobrien
88220176Sobrienint history_base = 1;		/* probably never subject to change */
89220176Sobrienint history_length = 0;
90220176Sobrienint max_input_history = 0;
91220176Sobrienchar history_expansion_char = '!';
92220176Sobrienchar history_subst_char = '^';
93220178Sobrienchar *history_no_expand_chars = expand_chars;
94220176SobrienFunction *history_inhibit_expansion_function = NULL;
95220178Sobrienchar *history_arg_extract(int start, int end, const char *str);
96220176Sobrien
97220176Sobrienint rl_inhibit_completion = 0;
98220176Sobrienint rl_attempted_completion_over = 0;
99220178Sobrienchar *rl_basic_word_break_characters = break_chars;
100220176Sobrienchar *rl_completer_word_break_characters = NULL;
101220176Sobrienchar *rl_completer_quote_characters = NULL;
102220178SobrienFunction *rl_completion_entry_function = NULL;
103220176SobrienCPPFunction *rl_attempted_completion_function = NULL;
104220178SobrienFunction *rl_pre_input_hook = NULL;
105220178SobrienFunction *rl_startup1_hook = NULL;
106220220Sobrienint (*rl_getc_function)(FILE *) = NULL;
107220178Sobrienchar *rl_terminal_name = NULL;
108220178Sobrienint rl_already_prompted = 0;
109220178Sobrienint rl_filename_completion_desired = 0;
110220178Sobrienint rl_ignore_completion_duplicates = 0;
111220178Sobrienint rl_catch_signals = 1;
112220218Sobrienint readline_echoing_p = 1;
113220218Sobrienint _rl_print_completions_horizontally = 0;
114220178SobrienVFunction *rl_redisplay_function = NULL;
115220178SobrienFunction *rl_startup_hook = NULL;
116220178SobrienVFunction *rl_completion_display_matches_hook = NULL;
117220218SobrienVFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal;
118220218SobrienVFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal;
119220220SobrienKEYMAP_ENTRY_ARRAY emacs_meta_keymap;
120220176Sobrien
121220220Sobrien#ifdef WIDECHAR
122220220Sobrienstatic ct_buffer_t conv;
123220220Sobrien#endif
124220220Sobrien
125220176Sobrien/*
126220178Sobrien * The current prompt string.
127220178Sobrien */
128220178Sobrienchar *rl_prompt = NULL;
129220178Sobrien/*
130220176Sobrien * This is set to character indicating type of completion being done by
131220176Sobrien * rl_complete_internal(); this is available for application completion
132220176Sobrien * functions.
133220176Sobrien */
134220176Sobrienint rl_completion_type = 0;
135220176Sobrien
136220176Sobrien/*
137220176Sobrien * If more than this number of items results from query for possible
138220176Sobrien * completions, we ask user if they are sure to really display the list.
139220176Sobrien */
140220176Sobrienint rl_completion_query_items = 100;
141220176Sobrien
142220176Sobrien/*
143220176Sobrien * List of characters which are word break characters, but should be left
144220176Sobrien * in the parsed text when it is passed to the completion function.
145220176Sobrien * Shell uses this to help determine what kind of completing to do.
146220176Sobrien */
147220178Sobrienchar *rl_special_prefixes = NULL;
148220176Sobrien
149220176Sobrien/*
150220176Sobrien * This is the character appended to the completed words if at the end of
151220176Sobrien * the line. Default is ' ' (a space).
152220176Sobrien */
153220176Sobrienint rl_completion_append_character = ' ';
154220176Sobrien
155220176Sobrien/* stuff below is used internally by libedit for readline emulation */
156220176Sobrien
157220220Sobrienstatic TYPE(History) *h = NULL;
158220176Sobrienstatic EditLine *e = NULL;
159220178Sobrienstatic Function *map[256];
160220218Sobrienstatic jmp_buf topbuf;
161220176Sobrien
162220176Sobrien/* internal functions */
163220176Sobrienstatic unsigned char	 _el_rl_complete(EditLine *, int);
164220178Sobrienstatic unsigned char	 _el_rl_tstp(EditLine *, int);
165220176Sobrienstatic char		*_get_prompt(EditLine *);
166220216Sobrienstatic int		 _getc_function(EditLine *, char *);
167220176Sobrienstatic HIST_ENTRY	*_move_history(int);
168220178Sobrienstatic int		 _history_expand_command(const char *, size_t, size_t,
169220178Sobrien    char **);
170220176Sobrienstatic char		*_rl_compat_sub(const char *, const char *,
171220178Sobrien    const char *, int);
172220178Sobrienstatic int		 _rl_event_read_char(EditLine *, char *);
173220178Sobrienstatic void		 _rl_update_pos(void);
174220176Sobrien
175220176Sobrien
176220176Sobrien/* ARGSUSED */
177220176Sobrienstatic char *
178220178Sobrien_get_prompt(EditLine *el __attribute__((__unused__)))
179220176Sobrien{
180220178Sobrien	rl_already_prompted = 1;
181220178Sobrien	return (rl_prompt);
182220176Sobrien}
183220176Sobrien
184220176Sobrien
185220176Sobrien/*
186220176Sobrien * generic function for moving around history
187220176Sobrien */
188220176Sobrienstatic HIST_ENTRY *
189220176Sobrien_move_history(int op)
190220176Sobrien{
191220220Sobrien	TYPE(HistEvent) ev;
192220176Sobrien	static HIST_ENTRY rl_he;
193220176Sobrien
194220220Sobrien	if (FUNW(history)(h, &ev, op) != 0)
195220176Sobrien		return (HIST_ENTRY *) NULL;
196220176Sobrien
197220220Sobrien	rl_he.line = ct_encode_string(ev.str, &conv);
198220178Sobrien	rl_he.data = NULL;
199220176Sobrien
200220176Sobrien	return (&rl_he);
201220176Sobrien}
202220176Sobrien
203220176Sobrien
204220176Sobrien/*
205220216Sobrien * read one key from user defined input function
206220216Sobrien */
207220216Sobrienstatic int
208220216Sobrien/*ARGSUSED*/
209220216Sobrien_getc_function(EditLine *el, char *c)
210220216Sobrien{
211220216Sobrien	int i;
212220216Sobrien
213220220Sobrien	i = (*rl_getc_function)(NULL);
214220216Sobrien	if (i == -1)
215220216Sobrien		return 0;
216220216Sobrien	*c = i;
217220216Sobrien	return 1;
218220216Sobrien}
219220216Sobrien
220220220Sobrienstatic const char _dothistory[] = "/.history";
221220216Sobrien
222220220Sobrienstatic const char *
223220220Sobrien_default_history_file(void)
224220220Sobrien{
225220220Sobrien	struct passwd *p;
226220220Sobrien	static char path[PATH_MAX];
227220220Sobrien
228220220Sobrien	if (*path)
229220220Sobrien		return path;
230220220Sobrien	if ((p = getpwuid(getuid())) == NULL)
231220220Sobrien		return NULL;
232220220Sobrien	strlcpy(path, p->pw_dir, PATH_MAX);
233220220Sobrien	strlcat(path, _dothistory, PATH_MAX);
234220220Sobrien	return path;
235220220Sobrien}
236220220Sobrien
237220216Sobrien/*
238220176Sobrien * READLINE compatibility stuff
239220176Sobrien */
240220176Sobrien
241220176Sobrien/*
242220220Sobrien * Set the prompt
243220220Sobrien */
244220220Sobrienint
245220220Sobrienrl_set_prompt(const char *prompt)
246220220Sobrien{
247220220Sobrien	char *p;
248220220Sobrien
249220220Sobrien	if (!prompt)
250220220Sobrien		prompt = "";
251220220Sobrien	if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0)
252220220Sobrien		return 0;
253220220Sobrien	if (rl_prompt)
254220220Sobrien		free(rl_prompt);
255220220Sobrien	rl_prompt = strdup(prompt);
256220220Sobrien	if (rl_prompt == NULL)
257220220Sobrien		return -1;
258220220Sobrien
259220220Sobrien	while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL)
260220220Sobrien		*p = RL_PROMPT_START_IGNORE;
261220220Sobrien
262220220Sobrien	return 0;
263220220Sobrien}
264220220Sobrien
265220220Sobrien/*
266220176Sobrien * initialize rl compat stuff
267220176Sobrien */
268220176Sobrienint
269220176Sobrienrl_initialize(void)
270220176Sobrien{
271220220Sobrien	TYPE(HistEvent) ev;
272220176Sobrien	const LineInfo *li;
273220176Sobrien	int editmode = 1;
274220176Sobrien	struct termios t;
275220176Sobrien
276220176Sobrien	if (e != NULL)
277220176Sobrien		el_end(e);
278220176Sobrien	if (h != NULL)
279220220Sobrien		FUN(history,end)(h);
280220176Sobrien
281220176Sobrien	if (!rl_instream)
282220176Sobrien		rl_instream = stdin;
283220176Sobrien	if (!rl_outstream)
284220176Sobrien		rl_outstream = stdout;
285220176Sobrien
286220176Sobrien	/*
287220176Sobrien	 * See if we don't really want to run the editor
288220176Sobrien	 */
289220176Sobrien	if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0)
290220176Sobrien		editmode = 0;
291220176Sobrien
292220176Sobrien	e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr);
293220176Sobrien
294220176Sobrien	if (!editmode)
295220220Sobrien		FUN(el,set)(e, EL_EDITMODE, 0);
296220176Sobrien
297220220Sobrien	h = FUN(history,init)();
298220176Sobrien	if (!e || !h)
299220176Sobrien		return (-1);
300220176Sobrien
301220220Sobrien	FUNW(history)(h, &ev, H_SETSIZE, INT_MAX);	/* unlimited */
302220176Sobrien	history_length = 0;
303220176Sobrien	max_input_history = INT_MAX;
304220176Sobrien	el_set(e, EL_HIST, history, h);
305220176Sobrien
306220216Sobrien	/* setup getc function if valid */
307220216Sobrien	if (rl_getc_function)
308220216Sobrien		el_set(e, EL_GETCFN, _getc_function);
309220216Sobrien
310220176Sobrien	/* for proper prompt printing in readline() */
311220220Sobrien	if (rl_set_prompt("") == -1) {
312220220Sobrien		FUN(history,end)(h);
313220178Sobrien		el_end(e);
314220178Sobrien		return -1;
315220178Sobrien	}
316220220Sobrien	el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE);
317220178Sobrien	el_set(e, EL_SIGNAL, rl_catch_signals);
318220176Sobrien
319220176Sobrien	/* set default mode to "emacs"-style and read setting afterwards */
320220176Sobrien	/* so this can be overriden */
321220176Sobrien	el_set(e, EL_EDITOR, "emacs");
322220178Sobrien	if (rl_terminal_name != NULL)
323220178Sobrien		el_set(e, EL_TERMINAL, rl_terminal_name);
324220178Sobrien	else
325220178Sobrien		el_get(e, EL_TERMINAL, &rl_terminal_name);
326220176Sobrien
327220176Sobrien	/*
328220178Sobrien	 * Word completion - this has to go AFTER rebinding keys
329220176Sobrien	 * to emacs-style.
330220176Sobrien	 */
331220176Sobrien	el_set(e, EL_ADDFN, "rl_complete",
332220178Sobrien	    "ReadLine compatible completion function",
333220176Sobrien	    _el_rl_complete);
334220176Sobrien	el_set(e, EL_BIND, "^I", "rl_complete", NULL);
335220176Sobrien
336220176Sobrien	/*
337220178Sobrien	 * Send TSTP when ^Z is pressed.
338220176Sobrien	 */
339220178Sobrien	el_set(e, EL_ADDFN, "rl_tstp",
340220178Sobrien	    "ReadLine compatible suspend function",
341220178Sobrien	    _el_rl_tstp);
342220178Sobrien	el_set(e, EL_BIND, "^Z", "rl_tstp", NULL);
343220176Sobrien
344220176Sobrien	/* read settings from configuration file */
345220176Sobrien	el_source(e, NULL);
346220176Sobrien
347220176Sobrien	/*
348220176Sobrien	 * Unfortunately, some applications really do use rl_point
349220176Sobrien	 * and rl_line_buffer directly.
350220176Sobrien	 */
351220176Sobrien	li = el_line(e);
352220178Sobrien	/* a cheesy way to get rid of const cast. */
353220178Sobrien	rl_line_buffer = memchr(li->buffer, *li->buffer, 1);
354220178Sobrien	_rl_update_pos();
355220176Sobrien
356220178Sobrien	if (rl_startup_hook)
357220178Sobrien		(*rl_startup_hook)(NULL, 0);
358220178Sobrien
359220176Sobrien	return (0);
360220176Sobrien}
361220176Sobrien
362220176Sobrien
363220176Sobrien/*
364220176Sobrien * read one line from input stream and return it, chomping
365220176Sobrien * trailing newline (if there is any)
366220176Sobrien */
367220176Sobrienchar *
368220218Sobrienreadline(const char *p)
369220176Sobrien{
370220220Sobrien	TYPE(HistEvent) ev;
371220218Sobrien	const char * volatile prompt = p;
372220176Sobrien	int count;
373220176Sobrien	const char *ret;
374220178Sobrien	char *buf;
375220178Sobrien	static int used_event_hook;
376220176Sobrien
377220176Sobrien	if (e == NULL || h == NULL)
378220176Sobrien		rl_initialize();
379220176Sobrien
380220178Sobrien	rl_done = 0;
381220178Sobrien
382220218Sobrien	(void)setjmp(topbuf);
383220218Sobrien
384220176Sobrien	/* update prompt accordingly to what has been passed */
385220220Sobrien	if (rl_set_prompt(prompt) == -1)
386220220Sobrien		return NULL;
387220178Sobrien
388220178Sobrien	if (rl_pre_input_hook)
389220178Sobrien		(*rl_pre_input_hook)(NULL, 0);
390220178Sobrien
391220178Sobrien	if (rl_event_hook && !(e->el_flags&NO_TTY)) {
392220178Sobrien		el_set(e, EL_GETCFN, _rl_event_read_char);
393220178Sobrien		used_event_hook = 1;
394220178Sobrien	}
395220178Sobrien
396220178Sobrien	if (!rl_event_hook && used_event_hook) {
397220178Sobrien		el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN);
398220178Sobrien		used_event_hook = 0;
399220178Sobrien	}
400220178Sobrien
401220178Sobrien	rl_already_prompted = 0;
402220178Sobrien
403220176Sobrien	/* get one line from input stream */
404220176Sobrien	ret = el_gets(e, &count);
405220176Sobrien
406220176Sobrien	if (ret && count > 0) {
407220176Sobrien		int lastidx;
408220176Sobrien
409220178Sobrien		buf = strdup(ret);
410220178Sobrien		if (buf == NULL)
411220178Sobrien			return NULL;
412220176Sobrien		lastidx = count - 1;
413220178Sobrien		if (buf[lastidx] == '\n')
414220178Sobrien			buf[lastidx] = '\0';
415220176Sobrien	} else
416220178Sobrien		buf = NULL;
417220176Sobrien
418220220Sobrien	FUNW(history)(h, &ev, H_GETSIZE);
419220176Sobrien	history_length = ev.num;
420220176Sobrien
421220178Sobrien	return buf;
422220176Sobrien}
423220176Sobrien
424220176Sobrien/*
425220176Sobrien * history functions
426220176Sobrien */
427220176Sobrien
428220176Sobrien/*
429220176Sobrien * is normally called before application starts to use
430220176Sobrien * history expansion functions
431220176Sobrien */
432220176Sobrienvoid
433220176Sobrienusing_history(void)
434220176Sobrien{
435220176Sobrien	if (h == NULL || e == NULL)
436220176Sobrien		rl_initialize();
437220176Sobrien}
438220176Sobrien
439220176Sobrien
440220176Sobrien/*
441220176Sobrien * substitute ``what'' with ``with'', returning resulting string; if
442220178Sobrien * globally == 1, substitutes all occurrences of what, otherwise only the
443220176Sobrien * first one
444220176Sobrien */
445220176Sobrienstatic char *
446220176Sobrien_rl_compat_sub(const char *str, const char *what, const char *with,
447220176Sobrien    int globally)
448220176Sobrien{
449220178Sobrien	const	char	*s;
450220178Sobrien	char	*r, *result;
451220178Sobrien	size_t	len, with_len, what_len;
452220176Sobrien
453220178Sobrien	len = strlen(str);
454220176Sobrien	with_len = strlen(with);
455220176Sobrien	what_len = strlen(what);
456220178Sobrien
457220178Sobrien	/* calculate length we need for result */
458220178Sobrien	s = str;
459220178Sobrien	while (*s) {
460220178Sobrien		if (*s == *what && !strncmp(s, what, what_len)) {
461220178Sobrien			len += with_len - what_len;
462220178Sobrien			if (!globally)
463220178Sobrien				break;
464220178Sobrien			s += what_len;
465220178Sobrien		} else
466220178Sobrien			s++;
467220178Sobrien	}
468220178Sobrien	r = result = malloc(len + 1);
469220178Sobrien	if (result == NULL)
470220178Sobrien		return NULL;
471220178Sobrien	s = str;
472220178Sobrien	while (*s) {
473220178Sobrien		if (*s == *what && !strncmp(s, what, what_len)) {
474220178Sobrien			(void)strncpy(r, with, with_len);
475220178Sobrien			r += with_len;
476220178Sobrien			s += what_len;
477220178Sobrien			if (!globally) {
478220178Sobrien				(void)strcpy(r, s);
479220178Sobrien				return(result);
480220176Sobrien			}
481220178Sobrien		} else
482220178Sobrien			*r++ = *s++;
483220178Sobrien	}
484220220Sobrien	*r = '\0';
485220178Sobrien	return(result);
486220178Sobrien}
487220178Sobrien
488220178Sobrienstatic	char	*last_search_pat;	/* last !?pat[?] search pattern */
489220178Sobrienstatic	char	*last_search_match;	/* last !?pat[?] that matched */
490220178Sobrien
491220178Sobrienconst char *
492220178Sobrienget_history_event(const char *cmd, int *cindex, int qchar)
493220178Sobrien{
494220178Sobrien	int idx, sign, sub, num, begin, ret;
495220178Sobrien	size_t len;
496220178Sobrien	char	*pat;
497220178Sobrien	const char *rptr;
498220220Sobrien	TYPE(HistEvent) ev;
499220178Sobrien
500220178Sobrien	idx = *cindex;
501220178Sobrien	if (cmd[idx++] != history_expansion_char)
502220178Sobrien		return(NULL);
503220178Sobrien
504220178Sobrien	/* find out which event to take */
505220220Sobrien	if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') {
506220220Sobrien		if (FUNW(history)(h, &ev, H_FIRST) != 0)
507220178Sobrien			return(NULL);
508220178Sobrien		*cindex = cmd[idx]? (idx + 1):idx;
509220220Sobrien		return ct_encode_string(ev.str, &conv);
510220178Sobrien	}
511220178Sobrien	sign = 0;
512220178Sobrien	if (cmd[idx] == '-') {
513220178Sobrien		sign = 1;
514220178Sobrien		idx++;
515220178Sobrien	}
516220178Sobrien
517220178Sobrien	if ('0' <= cmd[idx] && cmd[idx] <= '9') {
518220178Sobrien		HIST_ENTRY *rl_he;
519220178Sobrien
520220178Sobrien		num = 0;
521220178Sobrien		while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') {
522220178Sobrien			num = num * 10 + cmd[idx] - '0';
523220178Sobrien			idx++;
524220176Sobrien		}
525220178Sobrien		if (sign)
526220178Sobrien			num = history_length - num + 1;
527220176Sobrien
528220178Sobrien		if (!(rl_he = history_get(num)))
529220178Sobrien			return(NULL);
530220178Sobrien
531220178Sobrien		*cindex = idx;
532220178Sobrien		return(rl_he->line);
533220178Sobrien	}
534220178Sobrien	sub = 0;
535220178Sobrien	if (cmd[idx] == '?') {
536220178Sobrien		sub = 1;
537220178Sobrien		idx++;
538220178Sobrien	}
539220178Sobrien	begin = idx;
540220178Sobrien	while (cmd[idx]) {
541220178Sobrien		if (cmd[idx] == '\n')
542220178Sobrien			break;
543220178Sobrien		if (sub && cmd[idx] == '?')
544220178Sobrien			break;
545220178Sobrien		if (!sub && (cmd[idx] == ':' || cmd[idx] == ' '
546220178Sobrien				    || cmd[idx] == '\t' || cmd[idx] == qchar))
547220178Sobrien			break;
548220178Sobrien		idx++;
549220178Sobrien	}
550220178Sobrien	len = idx - begin;
551220178Sobrien	if (sub && cmd[idx] == '?')
552220178Sobrien		idx++;
553220178Sobrien	if (sub && len == 0 && last_search_pat && *last_search_pat)
554220178Sobrien		pat = last_search_pat;
555220178Sobrien	else if (len == 0)
556220178Sobrien		return(NULL);
557220178Sobrien	else {
558220178Sobrien		if ((pat = malloc(len + 1)) == NULL)
559220178Sobrien			return NULL;
560220178Sobrien		(void)strncpy(pat, cmd + begin, len);
561220178Sobrien		pat[len] = '\0';
562220178Sobrien	}
563220178Sobrien
564220220Sobrien	if (FUNW(history)(h, &ev, H_CURR) != 0) {
565220178Sobrien		if (pat != last_search_pat)
566220178Sobrien			free(pat);
567220178Sobrien		return (NULL);
568220178Sobrien	}
569220178Sobrien	num = ev.num;
570220178Sobrien
571220178Sobrien	if (sub) {
572220178Sobrien		if (pat != last_search_pat) {
573220178Sobrien			if (last_search_pat)
574220178Sobrien				free(last_search_pat);
575220178Sobrien			last_search_pat = pat;
576220178Sobrien		}
577220178Sobrien		ret = history_search(pat, -1);
578220178Sobrien	} else
579220178Sobrien		ret = history_search_prefix(pat, -1);
580220178Sobrien
581220178Sobrien	if (ret == -1) {
582220178Sobrien		/* restore to end of list on failed search */
583220220Sobrien		FUNW(history)(h, &ev, H_FIRST);
584220178Sobrien		(void)fprintf(rl_outstream, "%s: Event not found\n", pat);
585220178Sobrien		if (pat != last_search_pat)
586220178Sobrien			free(pat);
587220178Sobrien		return(NULL);
588220178Sobrien	}
589220178Sobrien
590220178Sobrien	if (sub && len) {
591220178Sobrien		if (last_search_match && last_search_match != pat)
592220178Sobrien			free(last_search_match);
593220178Sobrien		last_search_match = pat;
594220178Sobrien	}
595220178Sobrien
596220178Sobrien	if (pat != last_search_pat)
597220178Sobrien		free(pat);
598220178Sobrien
599220220Sobrien	if (FUNW(history)(h, &ev, H_CURR) != 0)
600220178Sobrien		return(NULL);
601220178Sobrien	*cindex = idx;
602220220Sobrien	rptr = ct_encode_string(ev.str, &conv);
603220178Sobrien
604220178Sobrien	/* roll back to original position */
605220220Sobrien	(void)FUNW(history)(h, &ev, H_SET, num);
606220178Sobrien
607220178Sobrien	return rptr;
608220176Sobrien}
609220176Sobrien
610220176Sobrien/*
611220176Sobrien * the real function doing history expansion - takes as argument command
612220176Sobrien * to do and data upon which the command should be executed
613220176Sobrien * does expansion the way I've understood readline documentation
614220176Sobrien *
615220176Sobrien * returns 0 if data was not modified, 1 if it was and 2 if the string
616220176Sobrien * should be only printed and not executed; in case of error,
617220176Sobrien * returns -1 and *result points to NULL
618220176Sobrien * it's callers responsibility to free() string returned in *result
619220176Sobrien */
620220176Sobrienstatic int
621220178Sobrien_history_expand_command(const char *command, size_t offs, size_t cmdlen,
622220178Sobrien    char **result)
623220176Sobrien{
624220178Sobrien	char *tmp, *search = NULL, *aptr;
625220178Sobrien	const char *ptr, *cmd;
626220176Sobrien	static char *from = NULL, *to = NULL;
627220178Sobrien	int start, end, idx, has_mods = 0;
628220178Sobrien	int p_on = 0, g_on = 0;
629220176Sobrien
630220176Sobrien	*result = NULL;
631220178Sobrien	aptr = NULL;
632220178Sobrien	ptr = NULL;
633220176Sobrien
634220178Sobrien	/* First get event specifier */
635220178Sobrien	idx = 0;
636220176Sobrien
637220178Sobrien	if (strchr(":^*$", command[offs + 1])) {
638220178Sobrien		char str[4];
639220178Sobrien		/*
640220178Sobrien		* "!:" is shorthand for "!!:".
641220178Sobrien		* "!^", "!*" and "!$" are shorthand for
642220178Sobrien		* "!!:^", "!!:*" and "!!:$" respectively.
643220178Sobrien		*/
644220178Sobrien		str[0] = str[1] = '!';
645220178Sobrien		str[2] = '0';
646220178Sobrien		ptr = get_history_event(str, &idx, 0);
647220178Sobrien		idx = (command[offs + 1] == ':')? 1:0;
648220178Sobrien		has_mods = 1;
649220176Sobrien	} else {
650220178Sobrien		if (command[offs + 1] == '#') {
651220178Sobrien			/* use command so far */
652220178Sobrien			if ((aptr = malloc(offs + 1)) == NULL)
653220178Sobrien				return -1;
654220178Sobrien			(void)strncpy(aptr, command, offs);
655220178Sobrien			aptr[offs] = '\0';
656220178Sobrien			idx = 1;
657220176Sobrien		} else {
658220178Sobrien			int	qchar;
659220176Sobrien
660220178Sobrien			qchar = (offs > 0 && command[offs - 1] == '"')? '"':0;
661220178Sobrien			ptr = get_history_event(command + offs, &idx, qchar);
662220178Sobrien		}
663220178Sobrien		has_mods = command[offs + idx] == ':';
664220178Sobrien	}
665220176Sobrien
666220178Sobrien	if (ptr == NULL && aptr == NULL)
667220178Sobrien		return(-1);
668220176Sobrien
669220178Sobrien	if (!has_mods) {
670220220Sobrien		*result = strdup(aptr ? aptr : ptr);
671220178Sobrien		if (aptr)
672220178Sobrien			free(aptr);
673220220Sobrien		if (*result == NULL)
674220220Sobrien			return -1;
675220178Sobrien		return(1);
676220178Sobrien	}
677220176Sobrien
678220178Sobrien	cmd = command + offs + idx + 1;
679220176Sobrien
680220178Sobrien	/* Now parse any word designators */
681220178Sobrien
682220178Sobrien	if (*cmd == '%')	/* last word matched by ?pat? */
683220178Sobrien		tmp = strdup(last_search_match? last_search_match:"");
684220178Sobrien	else if (strchr("^*$-0123456789", *cmd)) {
685220178Sobrien		start = end = -1;
686220178Sobrien		if (*cmd == '^')
687220178Sobrien			start = end = 1, cmd++;
688220178Sobrien		else if (*cmd == '$')
689220178Sobrien			start = -1, cmd++;
690220178Sobrien		else if (*cmd == '*')
691220178Sobrien			start = 1, cmd++;
692220178Sobrien	       else if (*cmd == '-' || isdigit((unsigned char) *cmd)) {
693220178Sobrien			start = 0;
694220178Sobrien			while (*cmd && '0' <= *cmd && *cmd <= '9')
695220178Sobrien				start = start * 10 + *cmd++ - '0';
696220178Sobrien
697220178Sobrien			if (*cmd == '-') {
698220178Sobrien				if (isdigit((unsigned char) cmd[1])) {
699220178Sobrien					cmd++;
700220178Sobrien					end = 0;
701220178Sobrien					while (*cmd && '0' <= *cmd && *cmd <= '9')
702220178Sobrien						end = end * 10 + *cmd++ - '0';
703220178Sobrien				} else if (cmd[1] == '$') {
704220178Sobrien					cmd += 2;
705220178Sobrien					end = -1;
706220178Sobrien				} else {
707220178Sobrien					cmd++;
708220178Sobrien					end = -2;
709220178Sobrien				}
710220178Sobrien			} else if (*cmd == '*')
711220178Sobrien				end = -1, cmd++;
712220178Sobrien			else
713220178Sobrien				end = start;
714220176Sobrien		}
715220178Sobrien		tmp = history_arg_extract(start, end, aptr? aptr:ptr);
716220178Sobrien		if (tmp == NULL) {
717220178Sobrien			(void)fprintf(rl_outstream, "%s: Bad word specifier",
718220178Sobrien			    command + offs + idx);
719220178Sobrien			if (aptr)
720220178Sobrien				free(aptr);
721220178Sobrien			return(-1);
722220178Sobrien		}
723220176Sobrien	} else
724220178Sobrien		tmp = strdup(aptr? aptr:ptr);
725220176Sobrien
726220178Sobrien	if (aptr)
727220178Sobrien		free(aptr);
728220176Sobrien
729220220Sobrien	if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) {
730220178Sobrien		*result = tmp;
731220178Sobrien		return(1);
732220176Sobrien	}
733220176Sobrien
734220176Sobrien	for (; *cmd; cmd++) {
735220176Sobrien		if (*cmd == ':')
736220176Sobrien			continue;
737220178Sobrien		else if (*cmd == 'h') {		/* remove trailing path */
738220178Sobrien			if ((aptr = strrchr(tmp, '/')) != NULL)
739220220Sobrien				*aptr = '\0';
740220178Sobrien		} else if (*cmd == 't') {	/* remove leading path */
741220178Sobrien			if ((aptr = strrchr(tmp, '/')) != NULL) {
742220178Sobrien				aptr = strdup(aptr + 1);
743220178Sobrien				free(tmp);
744220178Sobrien				tmp = aptr;
745220178Sobrien			}
746220178Sobrien		} else if (*cmd == 'r') {	/* remove trailing suffix */
747220178Sobrien			if ((aptr = strrchr(tmp, '.')) != NULL)
748220220Sobrien				*aptr = '\0';
749220178Sobrien		} else if (*cmd == 'e') {	/* remove all but suffix */
750220178Sobrien			if ((aptr = strrchr(tmp, '.')) != NULL) {
751220178Sobrien				aptr = strdup(aptr);
752220178Sobrien				free(tmp);
753220178Sobrien				tmp = aptr;
754220178Sobrien			}
755220178Sobrien		} else if (*cmd == 'p')		/* print only */
756220178Sobrien			p_on = 1;
757220176Sobrien		else if (*cmd == 'g')
758220176Sobrien			g_on = 2;
759220176Sobrien		else if (*cmd == 's' || *cmd == '&') {
760220176Sobrien			char *what, *with, delim;
761220178Sobrien			size_t len, from_len;
762220176Sobrien			size_t size;
763220176Sobrien
764220176Sobrien			if (*cmd == '&' && (from == NULL || to == NULL))
765220176Sobrien				continue;
766220176Sobrien			else if (*cmd == 's') {
767220176Sobrien				delim = *(++cmd), cmd++;
768220176Sobrien				size = 16;
769220176Sobrien				what = realloc(from, size);
770220178Sobrien				if (what == NULL) {
771220178Sobrien					free(from);
772220216Sobrien					free(tmp);
773220178Sobrien					return 0;
774220178Sobrien				}
775220176Sobrien				len = 0;
776220176Sobrien				for (; *cmd && *cmd != delim; cmd++) {
777220178Sobrien					if (*cmd == '\\' && cmd[1] == delim)
778220176Sobrien						cmd++;
779220178Sobrien					if (len >= size) {
780220178Sobrien						char *nwhat;
781220178Sobrien						nwhat = realloc(what,
782220178Sobrien								(size <<= 1));
783220178Sobrien						if (nwhat == NULL) {
784220178Sobrien							free(what);
785220216Sobrien							free(tmp);
786220178Sobrien							return 0;
787220178Sobrien						}
788220178Sobrien						what = nwhat;
789220178Sobrien					}
790220176Sobrien					what[len++] = *cmd;
791220176Sobrien				}
792220176Sobrien				what[len] = '\0';
793220176Sobrien				from = what;
794220176Sobrien				if (*what == '\0') {
795220176Sobrien					free(what);
796220178Sobrien					if (search) {
797220176Sobrien						from = strdup(search);
798220216Sobrien						if (from == NULL) {
799220216Sobrien							free(tmp);
800220178Sobrien							return 0;
801220216Sobrien						}
802220178Sobrien					} else {
803220176Sobrien						from = NULL;
804220216Sobrien						free(tmp);
805220176Sobrien						return (-1);
806220176Sobrien					}
807220176Sobrien				}
808220176Sobrien				cmd++;	/* shift after delim */
809220176Sobrien				if (!*cmd)
810220176Sobrien					continue;
811220176Sobrien
812220176Sobrien				size = 16;
813220176Sobrien				with = realloc(to, size);
814220178Sobrien				if (with == NULL) {
815220178Sobrien					free(to);
816220216Sobrien					free(tmp);
817220178Sobrien					return -1;
818220178Sobrien				}
819220176Sobrien				len = 0;
820220176Sobrien				from_len = strlen(from);
821220176Sobrien				for (; *cmd && *cmd != delim; cmd++) {
822220176Sobrien					if (len + from_len + 1 >= size) {
823220178Sobrien						char *nwith;
824220176Sobrien						size += from_len + 1;
825220178Sobrien						nwith = realloc(with, size);
826220178Sobrien						if (nwith == NULL) {
827220178Sobrien							free(with);
828220216Sobrien							free(tmp);
829220178Sobrien							return -1;
830220178Sobrien						}
831220178Sobrien						with = nwith;
832220176Sobrien					}
833220176Sobrien					if (*cmd == '&') {
834220176Sobrien						/* safe */
835220178Sobrien						(void)strcpy(&with[len], from);
836220176Sobrien						len += from_len;
837220176Sobrien						continue;
838220176Sobrien					}
839220176Sobrien					if (*cmd == '\\'
840220176Sobrien					    && (*(cmd + 1) == delim
841220176Sobrien						|| *(cmd + 1) == '&'))
842220176Sobrien						cmd++;
843220176Sobrien					with[len++] = *cmd;
844220176Sobrien				}
845220176Sobrien				with[len] = '\0';
846220176Sobrien				to = with;
847220178Sobrien			}
848220176Sobrien
849220178Sobrien			aptr = _rl_compat_sub(tmp, from, to, g_on);
850220178Sobrien			if (aptr) {
851220178Sobrien				free(tmp);
852220178Sobrien				tmp = aptr;
853220176Sobrien			}
854220178Sobrien			g_on = 0;
855220176Sobrien		}
856220176Sobrien	}
857220178Sobrien	*result = tmp;
858220178Sobrien	return (p_on? 2:1);
859220176Sobrien}
860220176Sobrien
861220176Sobrien
862220176Sobrien/*
863220176Sobrien * csh-style history expansion
864220176Sobrien */
865220176Sobrienint
866220176Sobrienhistory_expand(char *str, char **output)
867220176Sobrien{
868220178Sobrien	int ret = 0;
869220178Sobrien	size_t idx, i, size;
870220178Sobrien	char *tmp, *result;
871220176Sobrien
872220176Sobrien	if (h == NULL || e == NULL)
873220176Sobrien		rl_initialize();
874220176Sobrien
875220178Sobrien	if (history_expansion_char == 0) {
876220178Sobrien		*output = strdup(str);
877220178Sobrien		return(0);
878220178Sobrien	}
879220176Sobrien
880220178Sobrien	*output = NULL;
881220176Sobrien	if (str[0] == history_subst_char) {
882220176Sobrien		/* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
883220178Sobrien		*output = malloc(strlen(str) + 4 + 1);
884220178Sobrien		if (*output == NULL)
885220178Sobrien			return 0;
886220178Sobrien		(*output)[0] = (*output)[1] = history_expansion_char;
887220178Sobrien		(*output)[2] = ':';
888220178Sobrien		(*output)[3] = 's';
889220178Sobrien		(void)strcpy((*output) + 4, str);
890220178Sobrien		str = *output;
891220178Sobrien	} else {
892220178Sobrien		*output = strdup(str);
893220178Sobrien		if (*output == NULL)
894220178Sobrien			return 0;
895220176Sobrien	}
896220178Sobrien
897220216Sobrien#define ADD_STRING(what, len, fr)					\
898220176Sobrien	{								\
899220178Sobrien		if (idx + len + 1 > size) {				\
900220178Sobrien			char *nresult = realloc(result, (size += len + 1));\
901220178Sobrien			if (nresult == NULL) {				\
902220178Sobrien				free(*output);				\
903220216Sobrien				if (/*CONSTCOND*/fr)			\
904220216Sobrien					free(tmp);			\
905220178Sobrien				return 0;				\
906220178Sobrien			}						\
907220178Sobrien			result = nresult;				\
908220178Sobrien		}							\
909220176Sobrien		(void)strncpy(&result[idx], what, len);			\
910220176Sobrien		idx += len;						\
911220176Sobrien		result[idx] = '\0';					\
912220176Sobrien	}
913220176Sobrien
914220176Sobrien	result = NULL;
915220176Sobrien	size = idx = 0;
916220216Sobrien	tmp = NULL;
917220176Sobrien	for (i = 0; str[i];) {
918220178Sobrien		int qchar, loop_again;
919220178Sobrien		size_t len, start, j;
920220176Sobrien
921220178Sobrien		qchar = 0;
922220176Sobrien		loop_again = 1;
923220176Sobrien		start = j = i;
924220176Sobrienloop:
925220176Sobrien		for (; str[j]; j++) {
926220176Sobrien			if (str[j] == '\\' &&
927220176Sobrien			    str[j + 1] == history_expansion_char) {
928220178Sobrien				(void)strcpy(&str[j], &str[j + 1]);
929220176Sobrien				continue;
930220176Sobrien			}
931220176Sobrien			if (!loop_again) {
932220178Sobrien				if (isspace((unsigned char) str[j])
933220178Sobrien				    || str[j] == qchar)
934220176Sobrien					break;
935220176Sobrien			}
936220176Sobrien			if (str[j] == history_expansion_char
937220176Sobrien			    && !strchr(history_no_expand_chars, str[j + 1])
938220176Sobrien			    && (!history_inhibit_expansion_function ||
939220178Sobrien			    (*history_inhibit_expansion_function)(str,
940220178Sobrien			    (int)j) == 0))
941220176Sobrien				break;
942220176Sobrien		}
943220176Sobrien
944220178Sobrien		if (str[j] && loop_again) {
945220176Sobrien			i = j;
946220178Sobrien			qchar = (j > 0 && str[j - 1] == '"' )? '"':0;
947220176Sobrien			j++;
948220176Sobrien			if (str[j] == history_expansion_char)
949220176Sobrien				j++;
950220176Sobrien			loop_again = 0;
951220176Sobrien			goto loop;
952220176Sobrien		}
953220176Sobrien		len = i - start;
954220216Sobrien		ADD_STRING(&str[start], len, 0);
955220176Sobrien
956220178Sobrien		if (str[i] == '\0' || str[i] != history_expansion_char) {
957220176Sobrien			len = j - i;
958220216Sobrien			ADD_STRING(&str[i], len, 0);
959220176Sobrien			if (start == 0)
960220178Sobrien				ret = 0;
961220176Sobrien			else
962220178Sobrien				ret = 1;
963220176Sobrien			break;
964220176Sobrien		}
965220178Sobrien		ret = _history_expand_command (str, i, (j - i), &tmp);
966220178Sobrien		if (ret > 0 && tmp) {
967220178Sobrien			len = strlen(tmp);
968220216Sobrien			ADD_STRING(tmp, len, 1);
969220216Sobrien		}
970220216Sobrien		if (tmp) {
971220178Sobrien			free(tmp);
972220216Sobrien			tmp = NULL;
973220176Sobrien		}
974220176Sobrien		i = j;
975220178Sobrien	}
976220176Sobrien
977220178Sobrien	/* ret is 2 for "print only" option */
978220178Sobrien	if (ret == 2) {
979220178Sobrien		add_history(result);
980220176Sobrien#ifdef GDB_411_HACK
981220176Sobrien		/* gdb 4.11 has been shipped with readline, where */
982220176Sobrien		/* history_expand() returned -1 when the line	  */
983220176Sobrien		/* should not be executed; in readline 2.1+	  */
984220176Sobrien		/* it should return 2 in such a case		  */
985220178Sobrien		ret = -1;
986220176Sobrien#endif
987220176Sobrien	}
988220176Sobrien	free(*output);
989220176Sobrien	*output = result;
990220176Sobrien
991220178Sobrien	return (ret);
992220176Sobrien}
993220176Sobrien
994220178Sobrien/*
995220178Sobrien* Return a string consisting of arguments of "str" from "start" to "end".
996220178Sobrien*/
997220178Sobrienchar *
998220178Sobrienhistory_arg_extract(int start, int end, const char *str)
999220178Sobrien{
1000220178Sobrien	size_t  i, len, max;
1001220220Sobrien	char	**arr, *result = NULL;
1002220176Sobrien
1003220178Sobrien	arr = history_tokenize(str);
1004220178Sobrien	if (!arr)
1005220220Sobrien		return NULL;
1006220220Sobrien	if (arr && *arr == NULL)
1007220220Sobrien		goto out;
1008220178Sobrien
1009220178Sobrien	for (max = 0; arr[max]; max++)
1010220178Sobrien		continue;
1011220178Sobrien	max--;
1012220178Sobrien
1013220178Sobrien	if (start == '$')
1014220220Sobrien		start = (int)max;
1015220178Sobrien	if (end == '$')
1016220220Sobrien		end = (int)max;
1017220178Sobrien	if (end < 0)
1018220220Sobrien		end = (int)max + end + 1;
1019220178Sobrien	if (start < 0)
1020220178Sobrien		start = end;
1021220178Sobrien
1022220220Sobrien	if (start < 0 || end < 0 || (size_t)start > max ||
1023220220Sobrien	    (size_t)end > max || start > end)
1024220220Sobrien		goto out;
1025220178Sobrien
1026220220Sobrien	for (i = start, len = 0; i <= (size_t)end; i++)
1027220178Sobrien		len += strlen(arr[i]) + 1;
1028220178Sobrien	len++;
1029220178Sobrien	result = malloc(len);
1030220178Sobrien	if (result == NULL)
1031220220Sobrien		goto out;
1032220178Sobrien
1033220220Sobrien	for (i = start, len = 0; i <= (size_t)end; i++) {
1034220178Sobrien		(void)strcpy(result + len, arr[i]);
1035220178Sobrien		len += strlen(arr[i]);
1036220220Sobrien		if (i < (size_t)end)
1037220178Sobrien			result[len++] = ' ';
1038220178Sobrien	}
1039220220Sobrien	result[len] = '\0';
1040220178Sobrien
1041220220Sobrienout:
1042220178Sobrien	for (i = 0; arr[i]; i++)
1043220178Sobrien		free(arr[i]);
1044220178Sobrien	free(arr);
1045220178Sobrien
1046220220Sobrien	return result;
1047220178Sobrien}
1048220178Sobrien
1049220176Sobrien/*
1050220178Sobrien * Parse the string into individual tokens,
1051220178Sobrien * similar to how shell would do it.
1052220176Sobrien */
1053220176Sobrienchar **
1054220176Sobrienhistory_tokenize(const char *str)
1055220176Sobrien{
1056220178Sobrien	int size = 1, idx = 0, i, start;
1057220176Sobrien	size_t len;
1058220176Sobrien	char **result = NULL, *temp, delim = '\0';
1059220176Sobrien
1060220178Sobrien	for (i = 0; str[i];) {
1061220176Sobrien		while (isspace((unsigned char) str[i]))
1062220176Sobrien			i++;
1063220176Sobrien		start = i;
1064220178Sobrien		for (; str[i];) {
1065220176Sobrien			if (str[i] == '\\') {
1066220176Sobrien				if (str[i+1] != '\0')
1067220176Sobrien					i++;
1068220176Sobrien			} else if (str[i] == delim)
1069220176Sobrien				delim = '\0';
1070220176Sobrien			else if (!delim &&
1071220176Sobrien				    (isspace((unsigned char) str[i]) ||
1072220176Sobrien				strchr("()<>;&|$", str[i])))
1073220176Sobrien				break;
1074220176Sobrien			else if (!delim && strchr("'`\"", str[i]))
1075220176Sobrien				delim = str[i];
1076220178Sobrien			if (str[i])
1077220178Sobrien				i++;
1078220176Sobrien		}
1079220176Sobrien
1080220178Sobrien		if (idx + 2 >= size) {
1081220178Sobrien			char **nresult;
1082220176Sobrien			size <<= 1;
1083220178Sobrien			nresult = realloc(result, size * sizeof(char *));
1084220178Sobrien			if (nresult == NULL) {
1085220178Sobrien				free(result);
1086220178Sobrien				return NULL;
1087220178Sobrien			}
1088220178Sobrien			result = nresult;
1089220176Sobrien		}
1090220176Sobrien		len = i - start;
1091220176Sobrien		temp = malloc(len + 1);
1092220178Sobrien		if (temp == NULL) {
1093220178Sobrien			for (i = 0; i < idx; i++)
1094220178Sobrien				free(result[i]);
1095220178Sobrien			free(result);
1096220178Sobrien			return NULL;
1097220178Sobrien		}
1098220178Sobrien		(void)strncpy(temp, &str[start], len);
1099220176Sobrien		temp[len] = '\0';
1100220178Sobrien		result[idx++] = temp;
1101220178Sobrien		result[idx] = NULL;
1102220178Sobrien		if (str[i])
1103220178Sobrien			i++;
1104220176Sobrien	}
1105220176Sobrien	return (result);
1106220176Sobrien}
1107220176Sobrien
1108220176Sobrien
1109220176Sobrien/*
1110220176Sobrien * limit size of history record to ``max'' events
1111220176Sobrien */
1112220176Sobrienvoid
1113220176Sobrienstifle_history(int max)
1114220176Sobrien{
1115220220Sobrien	TYPE(HistEvent) ev;
1116220176Sobrien
1117220176Sobrien	if (h == NULL || e == NULL)
1118220176Sobrien		rl_initialize();
1119220176Sobrien
1120220220Sobrien	if (FUNW(history)(h, &ev, H_SETSIZE, max) == 0)
1121220176Sobrien		max_input_history = max;
1122220176Sobrien}
1123220176Sobrien
1124220176Sobrien
1125220176Sobrien/*
1126220176Sobrien * "unlimit" size of history - set the limit to maximum allowed int value
1127220176Sobrien */
1128220176Sobrienint
1129220176Sobrienunstifle_history(void)
1130220176Sobrien{
1131220220Sobrien	TYPE(HistEvent) ev;
1132220176Sobrien	int omax;
1133220176Sobrien
1134220220Sobrien	FUNW(history)(h, &ev, H_SETSIZE, INT_MAX);
1135220176Sobrien	omax = max_input_history;
1136220176Sobrien	max_input_history = INT_MAX;
1137220176Sobrien	return (omax);		/* some value _must_ be returned */
1138220176Sobrien}
1139220176Sobrien
1140220176Sobrien
1141220176Sobrienint
1142220176Sobrienhistory_is_stifled(void)
1143220176Sobrien{
1144220176Sobrien
1145220176Sobrien	/* cannot return true answer */
1146220176Sobrien	return (max_input_history != INT_MAX);
1147220176Sobrien}
1148220176Sobrien
1149220220Sobrienstatic const char _history_tmp_template[] = "/tmp/.historyXXXXXX";
1150220176Sobrien
1151220220Sobrienint
1152220220Sobrienhistory_truncate_file (const char *filename, int nlines)
1153220220Sobrien{
1154220220Sobrien	int ret = 0;
1155220220Sobrien	FILE *fp, *tp;
1156220220Sobrien	char template[sizeof(_history_tmp_template)];
1157220220Sobrien	char buf[4096];
1158220220Sobrien	int fd;
1159220220Sobrien	char *cp;
1160220220Sobrien	off_t off;
1161220220Sobrien	int count = 0;
1162220220Sobrien	ssize_t left = 0;
1163220220Sobrien
1164220220Sobrien	if (filename == NULL && (filename = _default_history_file()) == NULL)
1165220220Sobrien		return errno;
1166220220Sobrien	if ((fp = fopen(filename, "r+")) == NULL)
1167220220Sobrien		return errno;
1168220220Sobrien	strcpy(template, _history_tmp_template);
1169220220Sobrien	if ((fd = mkstemp(template)) == -1) {
1170220220Sobrien		ret = errno;
1171220220Sobrien		goto out1;
1172220220Sobrien	}
1173220220Sobrien
1174220220Sobrien	if ((tp = fdopen(fd, "r+")) == NULL) {
1175220220Sobrien		close(fd);
1176220220Sobrien		ret = errno;
1177220220Sobrien		goto out2;
1178220220Sobrien	}
1179220220Sobrien
1180220220Sobrien	for(;;) {
1181220220Sobrien		if (fread(buf, sizeof(buf), 1, fp) != 1) {
1182220220Sobrien			if (ferror(fp)) {
1183220220Sobrien				ret = errno;
1184220220Sobrien				break;
1185220220Sobrien			}
1186220220Sobrien			if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) ==
1187220220Sobrien			    (off_t)-1) {
1188220220Sobrien				ret = errno;
1189220220Sobrien				break;
1190220220Sobrien			}
1191220220Sobrien			left = fread(buf, 1, sizeof(buf), fp);
1192220220Sobrien			if (ferror(fp)) {
1193220220Sobrien				ret = errno;
1194220220Sobrien				break;
1195220220Sobrien			}
1196220220Sobrien			if (left == 0) {
1197220220Sobrien				count--;
1198220220Sobrien				left = sizeof(buf);
1199220220Sobrien			} else if (fwrite(buf, (size_t)left, 1, tp) != 1) {
1200220220Sobrien				ret = errno;
1201220220Sobrien				break;
1202220220Sobrien			}
1203220220Sobrien			fflush(tp);
1204220220Sobrien			break;
1205220220Sobrien		}
1206220220Sobrien		if (fwrite(buf, sizeof(buf), 1, tp) != 1) {
1207220220Sobrien			ret = errno;
1208220220Sobrien			break;
1209220220Sobrien		}
1210220220Sobrien		count++;
1211220220Sobrien	}
1212220220Sobrien	if (ret)
1213220220Sobrien		goto out3;
1214220220Sobrien	cp = buf + left - 1;
1215220220Sobrien	if(*cp != '\n')
1216220220Sobrien		cp++;
1217220220Sobrien	for(;;) {
1218220220Sobrien		while (--cp >= buf) {
1219220220Sobrien			if (*cp == '\n') {
1220220220Sobrien				if (--nlines == 0) {
1221220220Sobrien					if (++cp >= buf + sizeof(buf)) {
1222220220Sobrien						count++;
1223220220Sobrien						cp = buf;
1224220220Sobrien					}
1225220220Sobrien					break;
1226220220Sobrien				}
1227220220Sobrien			}
1228220220Sobrien		}
1229220220Sobrien		if (nlines <= 0 || count == 0)
1230220220Sobrien			break;
1231220220Sobrien		count--;
1232220220Sobrien		if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) {
1233220220Sobrien			ret = errno;
1234220220Sobrien			break;
1235220220Sobrien		}
1236220220Sobrien		if (fread(buf, sizeof(buf), 1, tp) != 1) {
1237220220Sobrien			if (ferror(tp)) {
1238220220Sobrien				ret = errno;
1239220220Sobrien				break;
1240220220Sobrien			}
1241220220Sobrien			ret = EAGAIN;
1242220220Sobrien			break;
1243220220Sobrien		}
1244220220Sobrien		cp = buf + sizeof(buf);
1245220220Sobrien	}
1246220220Sobrien
1247220220Sobrien	if (ret || nlines > 0)
1248220220Sobrien		goto out3;
1249220220Sobrien
1250220220Sobrien	if (fseeko(fp, 0, SEEK_SET) == (off_t)-1) {
1251220220Sobrien		ret = errno;
1252220220Sobrien		goto out3;
1253220220Sobrien	}
1254220220Sobrien
1255220220Sobrien	if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) ==
1256220220Sobrien	    (off_t)-1) {
1257220220Sobrien		ret = errno;
1258220220Sobrien		goto out3;
1259220220Sobrien	}
1260220220Sobrien
1261220220Sobrien	for(;;) {
1262220220Sobrien		if ((left = fread(buf, 1, sizeof(buf), tp)) == 0) {
1263220220Sobrien			if (ferror(fp))
1264220220Sobrien				ret = errno;
1265220220Sobrien			break;
1266220220Sobrien		}
1267220220Sobrien		if (fwrite(buf, (size_t)left, 1, fp) != 1) {
1268220220Sobrien			ret = errno;
1269220220Sobrien			break;
1270220220Sobrien		}
1271220220Sobrien	}
1272220220Sobrien	fflush(fp);
1273220220Sobrien	if((off = ftello(fp)) > 0)
1274220220Sobrien		(void)ftruncate(fileno(fp), off);
1275220220Sobrienout3:
1276220220Sobrien	fclose(tp);
1277220220Sobrienout2:
1278220220Sobrien	unlink(template);
1279220220Sobrienout1:
1280220220Sobrien	fclose(fp);
1281220220Sobrien
1282220220Sobrien	return ret;
1283220220Sobrien}
1284220220Sobrien
1285220220Sobrien
1286220176Sobrien/*
1287220176Sobrien * read history from a file given
1288220176Sobrien */
1289220176Sobrienint
1290220176Sobrienread_history(const char *filename)
1291220176Sobrien{
1292220220Sobrien	TYPE(HistEvent) ev;
1293220176Sobrien
1294220176Sobrien	if (h == NULL || e == NULL)
1295220176Sobrien		rl_initialize();
1296220220Sobrien	if (filename == NULL && (filename = _default_history_file()) == NULL)
1297220220Sobrien		return errno;
1298220220Sobrien	return (FUNW(history)(h, &ev, H_LOAD, filename) == -1 ?
1299220220Sobrien	    (errno ? errno : EINVAL) : 0);
1300220176Sobrien}
1301220176Sobrien
1302220176Sobrien
1303220176Sobrien/*
1304220176Sobrien * write history to a file given
1305220176Sobrien */
1306220176Sobrienint
1307220176Sobrienwrite_history(const char *filename)
1308220176Sobrien{
1309220220Sobrien	TYPE(HistEvent) ev;
1310220176Sobrien
1311220176Sobrien	if (h == NULL || e == NULL)
1312220176Sobrien		rl_initialize();
1313220220Sobrien	if (filename == NULL && (filename = _default_history_file()) == NULL)
1314220220Sobrien		return errno;
1315220220Sobrien	return (FUNW(history)(h, &ev, H_SAVE, filename) == -1 ?
1316220220Sobrien	    (errno ? errno : EINVAL) : 0);
1317220176Sobrien}
1318220176Sobrien
1319220176Sobrien
1320220176Sobrien/*
1321220176Sobrien * returns history ``num''th event
1322220176Sobrien *
1323220176Sobrien * returned pointer points to static variable
1324220176Sobrien */
1325220176SobrienHIST_ENTRY *
1326220176Sobrienhistory_get(int num)
1327220176Sobrien{
1328220176Sobrien	static HIST_ENTRY she;
1329220220Sobrien	TYPE(HistEvent) ev;
1330220178Sobrien	int curr_num;
1331220176Sobrien
1332220176Sobrien	if (h == NULL || e == NULL)
1333220176Sobrien		rl_initialize();
1334220176Sobrien
1335220178Sobrien	/* save current position */
1336220220Sobrien	if (FUNW(history)(h, &ev, H_CURR) != 0)
1337220176Sobrien		return (NULL);
1338220176Sobrien	curr_num = ev.num;
1339220178Sobrien
1340220220Sobrien	/* start from the oldest */
1341220220Sobrien	if (FUNW(history)(h, &ev, H_LAST) != 0)
1342220176Sobrien		return (NULL);	/* error */
1343220176Sobrien
1344220220Sobrien	/* look forwards for event matching specified offset */
1345220220Sobrien	if (FUNW(history)(h, &ev, H_NEXT_EVDATA, num, &she.data))
1346220178Sobrien		return (NULL);
1347220178Sobrien
1348220220Sobrien	she.line = ct_encode_string(ev.str, &conv);
1349220176Sobrien
1350220178Sobrien	/* restore pointer to where it was */
1351220220Sobrien	(void)FUNW(history)(h, &ev, H_SET, curr_num);
1352220176Sobrien
1353220176Sobrien	return (&she);
1354220176Sobrien}
1355220176Sobrien
1356220176Sobrien
1357220176Sobrien/*
1358220176Sobrien * add the line to history table
1359220176Sobrien */
1360220176Sobrienint
1361220176Sobrienadd_history(const char *line)
1362220176Sobrien{
1363220220Sobrien	TYPE(HistEvent) ev;
1364220220Sobrien	const Char *wline;
1365220176Sobrien
1366255891Sdelphij	if (line == NULL)
1367255891Sdelphij		return 0;
1368255891Sdelphij
1369220176Sobrien	if (h == NULL || e == NULL)
1370220176Sobrien		rl_initialize();
1371220176Sobrien
1372220220Sobrien	wline = ct_decode_string(line, &conv);
1373220220Sobrien
1374220220Sobrien	(void)FUNW(history)(h, &ev, H_ENTER, wline);
1375220220Sobrien	if (FUNW(history)(h, &ev, H_GETSIZE) == 0)
1376220176Sobrien		history_length = ev.num;
1377220176Sobrien
1378220178Sobrien	return (!(history_length > 0)); /* return 0 if all is okay */
1379220176Sobrien}
1380220176Sobrien
1381220176Sobrien
1382220176Sobrien/*
1383220178Sobrien * remove the specified entry from the history list and return it.
1384220178Sobrien */
1385220178SobrienHIST_ENTRY *
1386220178Sobrienremove_history(int num)
1387220178Sobrien{
1388220220Sobrien	HIST_ENTRY *he;
1389220220Sobrien	TYPE(HistEvent) ev;
1390220178Sobrien
1391220178Sobrien	if (h == NULL || e == NULL)
1392220178Sobrien		rl_initialize();
1393220178Sobrien
1394220220Sobrien	if ((he = malloc(sizeof(*he))) == NULL)
1395220178Sobrien		return NULL;
1396220178Sobrien
1397220220Sobrien	if (FUNW(history)(h, &ev, H_DELDATA, num, &he->data) != 0) {
1398220220Sobrien		free(he);
1399220220Sobrien		return NULL;
1400220220Sobrien	}
1401220178Sobrien
1402220220Sobrien	he->line = ct_encode_string(ev.str, &conv);
1403220220Sobrien	if (FUNW(history)(h, &ev, H_GETSIZE) == 0)
1404220220Sobrien		history_length = ev.num;
1405220220Sobrien
1406220220Sobrien	return he;
1407220178Sobrien}
1408220178Sobrien
1409220178Sobrien
1410220178Sobrien/*
1411220220Sobrien * replace the line and data of the num-th entry
1412220220Sobrien */
1413220220SobrienHIST_ENTRY *
1414220220Sobrienreplace_history_entry(int num, const char *line, histdata_t data)
1415220220Sobrien{
1416220220Sobrien	HIST_ENTRY *he;
1417220220Sobrien	TYPE(HistEvent) ev;
1418220220Sobrien	int curr_num;
1419220220Sobrien
1420220220Sobrien	if (h == NULL || e == NULL)
1421220220Sobrien		rl_initialize();
1422220220Sobrien
1423220220Sobrien	/* save current position */
1424220220Sobrien	if (FUNW(history)(h, &ev, H_CURR) != 0)
1425220220Sobrien		return NULL;
1426220220Sobrien	curr_num = ev.num;
1427220220Sobrien
1428220220Sobrien	/* start from the oldest */
1429220220Sobrien	if (FUNW(history)(h, &ev, H_LAST) != 0)
1430220220Sobrien		return NULL;	/* error */
1431220220Sobrien
1432220220Sobrien	if ((he = malloc(sizeof(*he))) == NULL)
1433220220Sobrien		return NULL;
1434220220Sobrien
1435220220Sobrien	/* look forwards for event matching specified offset */
1436220220Sobrien	if (FUNW(history)(h, &ev, H_NEXT_EVDATA, num, &he->data))
1437220220Sobrien		goto out;
1438220220Sobrien
1439220220Sobrien	he->line = strdup(ct_encode_string(ev.str, &e->el_scratch));
1440220220Sobrien	if (he->line == NULL)
1441220220Sobrien		goto out;
1442220220Sobrien
1443220220Sobrien	if (FUNW(history)(h, &ev, H_REPLACE, line, data))
1444220220Sobrien		goto out;
1445220220Sobrien
1446220220Sobrien	/* restore pointer to where it was */
1447220220Sobrien	if (FUNW(history)(h, &ev, H_SET, curr_num))
1448220220Sobrien		goto out;
1449220220Sobrien
1450220220Sobrien	return he;
1451220220Sobrienout:
1452220220Sobrien	free(he);
1453220220Sobrien	return NULL;
1454220220Sobrien}
1455220220Sobrien
1456220220Sobrien/*
1457220176Sobrien * clear the history list - delete all entries
1458220176Sobrien */
1459220176Sobrienvoid
1460220176Sobrienclear_history(void)
1461220176Sobrien{
1462220220Sobrien	TYPE(HistEvent) ev;
1463220176Sobrien
1464220220Sobrien	(void)FUNW(history)(h, &ev, H_CLEAR);
1465220220Sobrien	history_length = 0;
1466220176Sobrien}
1467220176Sobrien
1468220176Sobrien
1469220176Sobrien/*
1470220176Sobrien * returns offset of the current history event
1471220176Sobrien */
1472220176Sobrienint
1473220176Sobrienwhere_history(void)
1474220176Sobrien{
1475220220Sobrien	TYPE(HistEvent) ev;
1476220176Sobrien	int curr_num, off;
1477220176Sobrien
1478220220Sobrien	if (FUNW(history)(h, &ev, H_CURR) != 0)
1479220176Sobrien		return (0);
1480220176Sobrien	curr_num = ev.num;
1481220176Sobrien
1482220220Sobrien	(void)FUNW(history)(h, &ev, H_FIRST);
1483220176Sobrien	off = 1;
1484220220Sobrien	while (ev.num != curr_num && FUNW(history)(h, &ev, H_NEXT) == 0)
1485220176Sobrien		off++;
1486220176Sobrien
1487220176Sobrien	return (off);
1488220176Sobrien}
1489220176Sobrien
1490220176Sobrien
1491220176Sobrien/*
1492220176Sobrien * returns current history event or NULL if there is no such event
1493220176Sobrien */
1494220176SobrienHIST_ENTRY *
1495220176Sobriencurrent_history(void)
1496220176Sobrien{
1497220176Sobrien
1498220176Sobrien	return (_move_history(H_CURR));
1499220176Sobrien}
1500220176Sobrien
1501220176Sobrien
1502220176Sobrien/*
1503220176Sobrien * returns total number of bytes history events' data are using
1504220176Sobrien */
1505220176Sobrienint
1506220176Sobrienhistory_total_bytes(void)
1507220176Sobrien{
1508220220Sobrien	TYPE(HistEvent) ev;
1509220220Sobrien	int curr_num;
1510220220Sobrien	size_t size;
1511220176Sobrien
1512220220Sobrien	if (FUNW(history)(h, &ev, H_CURR) != 0)
1513220176Sobrien		return (-1);
1514220176Sobrien	curr_num = ev.num;
1515220176Sobrien
1516220220Sobrien	(void)FUNW(history)(h, &ev, H_FIRST);
1517220176Sobrien	size = 0;
1518220176Sobrien	do
1519220220Sobrien		size += Strlen(ev.str) * sizeof(*ev.str);
1520220220Sobrien	while (FUNW(history)(h, &ev, H_NEXT) == 0);
1521220176Sobrien
1522220176Sobrien	/* get to the same position as before */
1523220220Sobrien	FUNW(history)(h, &ev, H_PREV_EVENT, curr_num);
1524220176Sobrien
1525220220Sobrien	return (int)(size);
1526220176Sobrien}
1527220176Sobrien
1528220176Sobrien
1529220176Sobrien/*
1530220176Sobrien * sets the position in the history list to ``pos''
1531220176Sobrien */
1532220176Sobrienint
1533220176Sobrienhistory_set_pos(int pos)
1534220176Sobrien{
1535220220Sobrien	TYPE(HistEvent) ev;
1536220178Sobrien	int curr_num;
1537220176Sobrien
1538220220Sobrien	if (pos >= history_length || pos < 0)
1539220176Sobrien		return (-1);
1540220176Sobrien
1541220220Sobrien	(void)FUNW(history)(h, &ev, H_CURR);
1542220176Sobrien	curr_num = ev.num;
1543220176Sobrien
1544220220Sobrien	/*
1545220220Sobrien	 * use H_DELDATA to set to nth history (without delete) by passing
1546220220Sobrien	 * (void **)-1
1547220220Sobrien	 */
1548220220Sobrien	if (FUNW(history)(h, &ev, H_DELDATA, pos, (void **)-1)) {
1549220220Sobrien		(void)FUNW(history)(h, &ev, H_SET, curr_num);
1550220178Sobrien		return(-1);
1551220176Sobrien	}
1552220176Sobrien	return (0);
1553220176Sobrien}
1554220176Sobrien
1555220176Sobrien
1556220176Sobrien/*
1557220176Sobrien * returns previous event in history and shifts pointer accordingly
1558220176Sobrien */
1559220176SobrienHIST_ENTRY *
1560220176Sobrienprevious_history(void)
1561220176Sobrien{
1562220176Sobrien
1563220176Sobrien	return (_move_history(H_PREV));
1564220176Sobrien}
1565220176Sobrien
1566220176Sobrien
1567220176Sobrien/*
1568220176Sobrien * returns next event in history and shifts pointer accordingly
1569220176Sobrien */
1570220176SobrienHIST_ENTRY *
1571220176Sobriennext_history(void)
1572220176Sobrien{
1573220176Sobrien
1574220176Sobrien	return (_move_history(H_NEXT));
1575220176Sobrien}
1576220176Sobrien
1577220176Sobrien
1578220176Sobrien/*
1579220178Sobrien * searches for first history event containing the str
1580220176Sobrien */
1581220178Sobrienint
1582220178Sobrienhistory_search(const char *str, int direction)
1583220176Sobrien{
1584220220Sobrien	TYPE(HistEvent) ev;
1585220220Sobrien	const Char *strp;
1586220220Sobrien	const Char *wstr;
1587220176Sobrien	int curr_num;
1588220176Sobrien
1589220220Sobrien	if (FUNW(history)(h, &ev, H_CURR) != 0)
1590220176Sobrien		return (-1);
1591220176Sobrien	curr_num = ev.num;
1592220176Sobrien
1593220220Sobrien	wstr = ct_decode_string(str, &conv);
1594220176Sobrien	for (;;) {
1595220220Sobrien		if ((strp = Strstr(ev.str, wstr)) != NULL)
1596220176Sobrien			return (int) (strp - ev.str);
1597220220Sobrien		if (FUNW(history)(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0)
1598220176Sobrien			break;
1599220176Sobrien	}
1600220220Sobrien	(void)FUNW(history)(h, &ev, H_SET, curr_num);
1601220176Sobrien	return (-1);
1602220176Sobrien}
1603220176Sobrien
1604220176Sobrien
1605220176Sobrien/*
1606220176Sobrien * searches for first history event beginning with str
1607220176Sobrien */
1608220176Sobrienint
1609220176Sobrienhistory_search_prefix(const char *str, int direction)
1610220176Sobrien{
1611220220Sobrien	TYPE(HistEvent) ev;
1612220176Sobrien
1613220220Sobrien	return (FUNW(history)(h, &ev, direction < 0 ?
1614220220Sobrien	    H_PREV_STR : H_NEXT_STR, str));
1615220176Sobrien}
1616220176Sobrien
1617220176Sobrien
1618220176Sobrien/*
1619220176Sobrien * search for event in history containing str, starting at offset
1620220176Sobrien * abs(pos); continue backward, if pos<0, forward otherwise
1621220176Sobrien */
1622220176Sobrien/* ARGSUSED */
1623220176Sobrienint
1624220178Sobrienhistory_search_pos(const char *str,
1625220178Sobrien		   int direction __attribute__((__unused__)), int pos)
1626220176Sobrien{
1627220220Sobrien	TYPE(HistEvent) ev;
1628220176Sobrien	int curr_num, off;
1629220220Sobrien	const Char *wstr;
1630220176Sobrien
1631220176Sobrien	off = (pos > 0) ? pos : -pos;
1632220176Sobrien	pos = (pos > 0) ? 1 : -1;
1633220176Sobrien
1634220220Sobrien	if (FUNW(history)(h, &ev, H_CURR) != 0)
1635220176Sobrien		return (-1);
1636220176Sobrien	curr_num = ev.num;
1637220176Sobrien
1638220220Sobrien	if (history_set_pos(off) != 0 || FUNW(history)(h, &ev, H_CURR) != 0)
1639220176Sobrien		return (-1);
1640220176Sobrien
1641220220Sobrien	wstr = ct_decode_string(str, &conv);
1642220176Sobrien	for (;;) {
1643220220Sobrien		if (Strstr(ev.str, wstr))
1644220176Sobrien			return (off);
1645220220Sobrien		if (FUNW(history)(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0)
1646220176Sobrien			break;
1647220176Sobrien	}
1648220176Sobrien
1649220176Sobrien	/* set "current" pointer back to previous state */
1650220220Sobrien	(void)FUNW(history)(h, &ev,
1651220220Sobrien	    pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
1652220176Sobrien
1653220176Sobrien	return (-1);
1654220176Sobrien}
1655220176Sobrien
1656220176Sobrien
1657220176Sobrien/********************************/
1658220178Sobrien/* completion functions */
1659220176Sobrien
1660220176Sobrienchar *
1661220178Sobrientilde_expand(char *name)
1662220176Sobrien{
1663220178Sobrien	return fn_tilde_expand(name);
1664220176Sobrien}
1665220176Sobrien
1666220176Sobrienchar *
1667220178Sobrienfilename_completion_function(const char *name, int state)
1668220176Sobrien{
1669220178Sobrien	return fn_filename_completion_function(name, state);
1670220176Sobrien}
1671220176Sobrien
1672220176Sobrien/*
1673220176Sobrien * a completion generator for usernames; returns _first_ username
1674220176Sobrien * which starts with supplied text
1675220176Sobrien * text contains a partial username preceded by random character
1676220176Sobrien * (usually '~'); state is ignored
1677220176Sobrien * it's callers responsibility to free returned value
1678220176Sobrien */
1679220176Sobrienchar *
1680220176Sobrienusername_completion_function(const char *text, int state)
1681220176Sobrien{
1682220178Sobrien	struct passwd *pwd, pwres;
1683220178Sobrien	char pwbuf[1024];
1684220176Sobrien
1685220176Sobrien	if (text[0] == '\0')
1686220176Sobrien		return (NULL);
1687220176Sobrien
1688220176Sobrien	if (*text == '~')
1689220176Sobrien		text++;
1690220176Sobrien
1691220176Sobrien	if (state == 0)
1692220176Sobrien		setpwent();
1693220176Sobrien
1694220178Sobrien	while (getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pwd) == 0
1695220178Sobrien	    && pwd != NULL && text[0] == pwd->pw_name[0]
1696220176Sobrien	    && strcmp(text, pwd->pw_name) == 0);
1697220176Sobrien
1698220176Sobrien	if (pwd == NULL) {
1699220176Sobrien		endpwent();
1700220220Sobrien		return NULL;
1701220176Sobrien	}
1702220220Sobrien	return strdup(pwd->pw_name);
1703220176Sobrien}
1704220176Sobrien
1705220176Sobrien
1706220176Sobrien/*
1707220178Sobrien * el-compatible wrapper to send TSTP on ^Z
1708220176Sobrien */
1709220176Sobrien/* ARGSUSED */
1710220176Sobrienstatic unsigned char
1711220178Sobrien_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__)))
1712220176Sobrien{
1713220178Sobrien	(void)kill(0, SIGTSTP);
1714220178Sobrien	return CC_NORM;
1715220176Sobrien}
1716220176Sobrien
1717220176Sobrien/*
1718220176Sobrien * Display list of strings in columnar format on readline's output stream.
1719220176Sobrien * 'matches' is list of strings, 'len' is number of strings in 'matches',
1720220176Sobrien * 'max' is maximum length of string in 'matches'.
1721220176Sobrien */
1722220176Sobrienvoid
1723220178Sobrienrl_display_match_list(char **matches, int len, int max)
1724220176Sobrien{
1725220176Sobrien
1726220220Sobrien	fn_display_match_list(e, matches, (size_t)len, (size_t)max);
1727220176Sobrien}
1728220176Sobrien
1729220178Sobrienstatic const char *
1730220178Sobrien/*ARGSUSED*/
1731220178Sobrien_rl_completion_append_character_function(const char *dummy
1732220178Sobrien    __attribute__((__unused__)))
1733220176Sobrien{
1734220178Sobrien	static char buf[2];
1735220220Sobrien	buf[0] = rl_completion_append_character;
1736220220Sobrien	buf[1] = '\0';
1737220178Sobrien	return buf;
1738220176Sobrien}
1739220176Sobrien
1740220176Sobrien
1741220176Sobrien/*
1742220176Sobrien * complete word at current point
1743220176Sobrien */
1744220178Sobrien/* ARGSUSED */
1745220176Sobrienint
1746220178Sobrienrl_complete(int ignore __attribute__((__unused__)), int invoking_key)
1747220176Sobrien{
1748220220Sobrien#ifdef WIDECHAR
1749220220Sobrien	static ct_buffer_t wbreak_conv, sprefix_conv;
1750220220Sobrien#endif
1751220220Sobrien
1752220176Sobrien	if (h == NULL || e == NULL)
1753220176Sobrien		rl_initialize();
1754220176Sobrien
1755220176Sobrien	if (rl_inhibit_completion) {
1756220178Sobrien		char arr[2];
1757220178Sobrien		arr[0] = (char)invoking_key;
1758220178Sobrien		arr[1] = '\0';
1759220178Sobrien		el_insertstr(e, arr);
1760220176Sobrien		return (CC_REFRESH);
1761220178Sobrien	}
1762220178Sobrien
1763220178Sobrien	/* Just look at how many global variables modify this operation! */
1764220178Sobrien	return fn_complete(e,
1765220178Sobrien	    (CPFunction *)rl_completion_entry_function,
1766220178Sobrien	    rl_attempted_completion_function,
1767220220Sobrien	    ct_decode_string(rl_basic_word_break_characters, &wbreak_conv),
1768220220Sobrien	    ct_decode_string(rl_special_prefixes, &sprefix_conv),
1769220220Sobrien	    _rl_completion_append_character_function,
1770220220Sobrien	    (size_t)rl_completion_query_items,
1771220178Sobrien	    &rl_completion_type, &rl_attempted_completion_over,
1772220370Sobrien	    &rl_point, &rl_end, NULL, NULL, NULL);
1773220176Sobrien}
1774220176Sobrien
1775220176Sobrien
1776220178Sobrien/* ARGSUSED */
1777220178Sobrienstatic unsigned char
1778220178Sobrien_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch)
1779220178Sobrien{
1780220178Sobrien	return (unsigned char)rl_complete(0, ch);
1781220178Sobrien}
1782220178Sobrien
1783220176Sobrien/*
1784220176Sobrien * misc other functions
1785220176Sobrien */
1786220176Sobrien
1787220176Sobrien/*
1788220176Sobrien * bind key c to readline-type function func
1789220176Sobrien */
1790220176Sobrienint
1791220220Sobrienrl_bind_key(int c, rl_command_func_t *func)
1792220176Sobrien{
1793220176Sobrien	int retval = -1;
1794220176Sobrien
1795220176Sobrien	if (h == NULL || e == NULL)
1796220176Sobrien		rl_initialize();
1797220176Sobrien
1798220176Sobrien	if (func == rl_insert) {
1799220176Sobrien		/* XXX notice there is no range checking of ``c'' */
1800220176Sobrien		e->el_map.key[c] = ED_INSERT;
1801220176Sobrien		retval = 0;
1802220176Sobrien	}
1803220176Sobrien	return (retval);
1804220176Sobrien}
1805220176Sobrien
1806220176Sobrien
1807220176Sobrien/*
1808220176Sobrien * read one key from input - handles chars pushed back
1809220176Sobrien * to input stream also
1810220176Sobrien */
1811220176Sobrienint
1812220176Sobrienrl_read_key(void)
1813220176Sobrien{
1814220176Sobrien	char fooarr[2 * sizeof(int)];
1815220176Sobrien
1816220176Sobrien	if (e == NULL || h == NULL)
1817220176Sobrien		rl_initialize();
1818220176Sobrien
1819220176Sobrien	return (el_getc(e, fooarr));
1820220176Sobrien}
1821220176Sobrien
1822220176Sobrien
1823220176Sobrien/*
1824220176Sobrien * reset the terminal
1825220176Sobrien */
1826220176Sobrien/* ARGSUSED */
1827220176Sobrienvoid
1828220178Sobrienrl_reset_terminal(const char *p __attribute__((__unused__)))
1829220176Sobrien{
1830220176Sobrien
1831220176Sobrien	if (h == NULL || e == NULL)
1832220176Sobrien		rl_initialize();
1833220176Sobrien	el_reset(e);
1834220176Sobrien}
1835220176Sobrien
1836220176Sobrien
1837220176Sobrien/*
1838220176Sobrien * insert character ``c'' back into input stream, ``count'' times
1839220176Sobrien */
1840220176Sobrienint
1841220176Sobrienrl_insert(int count, int c)
1842220176Sobrien{
1843220176Sobrien	char arr[2];
1844220176Sobrien
1845220176Sobrien	if (h == NULL || e == NULL)
1846220176Sobrien		rl_initialize();
1847220176Sobrien
1848220176Sobrien	/* XXX - int -> char conversion can lose on multichars */
1849220176Sobrien	arr[0] = c;
1850220176Sobrien	arr[1] = '\0';
1851220176Sobrien
1852220176Sobrien	for (; count > 0; count--)
1853220176Sobrien		el_push(e, arr);
1854220176Sobrien
1855220176Sobrien	return (0);
1856220176Sobrien}
1857220178Sobrien
1858220220Sobrienint
1859220220Sobrienrl_insert_text(const char *text)
1860220220Sobrien{
1861220220Sobrien	if (!text || *text == 0)
1862220220Sobrien		return (0);
1863220220Sobrien
1864220220Sobrien	if (h == NULL || e == NULL)
1865220220Sobrien		rl_initialize();
1866220220Sobrien
1867220220Sobrien	if (el_insertstr(e, text) < 0)
1868220220Sobrien		return (0);
1869220220Sobrien	return (int)strlen(text);
1870220220Sobrien}
1871220220Sobrien
1872220178Sobrien/*ARGSUSED*/
1873220178Sobrienint
1874220178Sobrienrl_newline(int count, int c)
1875220178Sobrien{
1876220178Sobrien	/*
1877220178Sobrien	 * Readline-4.0 appears to ignore the args.
1878220178Sobrien	 */
1879220178Sobrien	return rl_insert(1, '\n');
1880220178Sobrien}
1881220178Sobrien
1882220178Sobrien/*ARGSUSED*/
1883220178Sobrienstatic unsigned char
1884220178Sobrienrl_bind_wrapper(EditLine *el, unsigned char c)
1885220178Sobrien{
1886220178Sobrien	if (map[c] == NULL)
1887220178Sobrien	    return CC_ERROR;
1888220178Sobrien
1889220178Sobrien	_rl_update_pos();
1890220178Sobrien
1891220178Sobrien	(*map[c])(NULL, c);
1892220178Sobrien
1893220178Sobrien	/* If rl_done was set by the above call, deal with it here */
1894220178Sobrien	if (rl_done)
1895220178Sobrien		return CC_EOF;
1896220178Sobrien
1897220178Sobrien	return CC_NORM;
1898220178Sobrien}
1899220178Sobrien
1900220178Sobrienint
1901220178Sobrienrl_add_defun(const char *name, Function *fun, int c)
1902220178Sobrien{
1903220178Sobrien	char dest[8];
1904220220Sobrien	if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0)
1905220178Sobrien		return -1;
1906220178Sobrien	map[(unsigned char)c] = fun;
1907220178Sobrien	el_set(e, EL_ADDFN, name, name, rl_bind_wrapper);
1908220178Sobrien	vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0);
1909220178Sobrien	el_set(e, EL_BIND, dest, name);
1910220178Sobrien	return 0;
1911220178Sobrien}
1912220178Sobrien
1913220178Sobrienvoid
1914220178Sobrienrl_callback_read_char()
1915220178Sobrien{
1916220178Sobrien	int count = 0, done = 0;
1917220178Sobrien	const char *buf = el_gets(e, &count);
1918220178Sobrien	char *wbuf;
1919220178Sobrien
1920220178Sobrien	if (buf == NULL || count-- <= 0)
1921220178Sobrien		return;
1922220216Sobrien	if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF])
1923220178Sobrien		done = 1;
1924220178Sobrien	if (buf[count] == '\n' || buf[count] == '\r')
1925220178Sobrien		done = 2;
1926220178Sobrien
1927220178Sobrien	if (done && rl_linefunc != NULL) {
1928220178Sobrien		el_set(e, EL_UNBUFFERED, 0);
1929220178Sobrien		if (done == 2) {
1930220178Sobrien		    if ((wbuf = strdup(buf)) != NULL)
1931220178Sobrien			wbuf[count] = '\0';
1932220178Sobrien		} else
1933220178Sobrien			wbuf = NULL;
1934220178Sobrien		(*(void (*)(const char *))rl_linefunc)(wbuf);
1935220220Sobrien		//el_set(e, EL_UNBUFFERED, 1);
1936220178Sobrien	}
1937220178Sobrien}
1938220178Sobrien
1939220178Sobrienvoid
1940220220Sobrienrl_callback_handler_install(const char *prompt, VCPFunction *linefunc)
1941220178Sobrien{
1942220178Sobrien	if (e == NULL) {
1943220178Sobrien		rl_initialize();
1944220178Sobrien	}
1945220220Sobrien	(void)rl_set_prompt(prompt);
1946220178Sobrien	rl_linefunc = linefunc;
1947220178Sobrien	el_set(e, EL_UNBUFFERED, 1);
1948220178Sobrien}
1949220178Sobrien
1950220178Sobrienvoid
1951220178Sobrienrl_callback_handler_remove(void)
1952220178Sobrien{
1953220178Sobrien	el_set(e, EL_UNBUFFERED, 0);
1954220220Sobrien	rl_linefunc = NULL;
1955220178Sobrien}
1956220178Sobrien
1957220178Sobrienvoid
1958220178Sobrienrl_redisplay(void)
1959220178Sobrien{
1960220178Sobrien	char a[2];
1961220216Sobrien	a[0] = e->el_tty.t_c[TS_IO][C_REPRINT];
1962220178Sobrien	a[1] = '\0';
1963220178Sobrien	el_push(e, a);
1964220178Sobrien}
1965220178Sobrien
1966220178Sobrienint
1967220178Sobrienrl_get_previous_history(int count, int key)
1968220178Sobrien{
1969220178Sobrien	char a[2];
1970220178Sobrien	a[0] = key;
1971220178Sobrien	a[1] = '\0';
1972220178Sobrien	while (count--)
1973220178Sobrien		el_push(e, a);
1974220178Sobrien	return 0;
1975220178Sobrien}
1976220178Sobrien
1977220178Sobrienvoid
1978220178Sobrien/*ARGSUSED*/
1979220178Sobrienrl_prep_terminal(int meta_flag)
1980220178Sobrien{
1981220178Sobrien	el_set(e, EL_PREP_TERM, 1);
1982220178Sobrien}
1983220178Sobrien
1984220178Sobrienvoid
1985220218Sobrienrl_deprep_terminal(void)
1986220178Sobrien{
1987220178Sobrien	el_set(e, EL_PREP_TERM, 0);
1988220178Sobrien}
1989220178Sobrien
1990220178Sobrienint
1991220178Sobrienrl_read_init_file(const char *s)
1992220178Sobrien{
1993220178Sobrien	return(el_source(e, s));
1994220178Sobrien}
1995220178Sobrien
1996220178Sobrienint
1997220178Sobrienrl_parse_and_bind(const char *line)
1998220178Sobrien{
1999220178Sobrien	const char **argv;
2000220178Sobrien	int argc;
2001220178Sobrien	Tokenizer *tok;
2002220178Sobrien
2003220178Sobrien	tok = tok_init(NULL);
2004220178Sobrien	tok_str(tok, line, &argc, &argv);
2005220178Sobrien	argc = el_parse(e, argc, argv);
2006220178Sobrien	tok_end(tok);
2007220178Sobrien	return (argc ? 1 : 0);
2008220178Sobrien}
2009220178Sobrien
2010220178Sobrienint
2011220178Sobrienrl_variable_bind(const char *var, const char *value)
2012220178Sobrien{
2013220178Sobrien	/*
2014220178Sobrien	 * The proper return value is undocument, but this is what the
2015220178Sobrien	 * readline source seems to do.
2016220178Sobrien	 */
2017220178Sobrien	return ((el_set(e, EL_BIND, "", var, value) == -1) ? 1 : 0);
2018220178Sobrien}
2019220178Sobrien
2020220178Sobrienvoid
2021220178Sobrienrl_stuff_char(int c)
2022220178Sobrien{
2023220178Sobrien	char buf[2];
2024220178Sobrien
2025220178Sobrien	buf[0] = c;
2026220178Sobrien	buf[1] = '\0';
2027220178Sobrien	el_insertstr(e, buf);
2028220178Sobrien}
2029220178Sobrien
2030220178Sobrienstatic int
2031220178Sobrien_rl_event_read_char(EditLine *el, char *cp)
2032220178Sobrien{
2033220220Sobrien	int	n;
2034220220Sobrien	ssize_t num_read = 0;
2035220178Sobrien
2036220220Sobrien	*cp = '\0';
2037220178Sobrien	while (rl_event_hook) {
2038220178Sobrien
2039220178Sobrien		(*rl_event_hook)();
2040220178Sobrien
2041220178Sobrien#if defined(FIONREAD)
2042220178Sobrien		if (ioctl(el->el_infd, FIONREAD, &n) < 0)
2043220178Sobrien			return(-1);
2044220178Sobrien		if (n)
2045220178Sobrien			num_read = read(el->el_infd, cp, 1);
2046220178Sobrien		else
2047220178Sobrien			num_read = 0;
2048220178Sobrien#elif defined(F_SETFL) && defined(O_NDELAY)
2049220178Sobrien		if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0)
2050220178Sobrien			return(-1);
2051220178Sobrien		if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0)
2052220178Sobrien			return(-1);
2053220178Sobrien		num_read = read(el->el_infd, cp, 1);
2054220178Sobrien		if (fcntl(el->el_infd, F_SETFL, n))
2055220178Sobrien			return(-1);
2056220178Sobrien#else
2057220178Sobrien		/* not non-blocking, but what you gonna do? */
2058220178Sobrien		num_read = read(el->el_infd, cp, 1);
2059220178Sobrien		return(-1);
2060220178Sobrien#endif
2061220178Sobrien
2062220178Sobrien		if (num_read < 0 && errno == EAGAIN)
2063220178Sobrien			continue;
2064220178Sobrien		if (num_read == 0)
2065220178Sobrien			continue;
2066220178Sobrien		break;
2067220178Sobrien	}
2068220178Sobrien	if (!rl_event_hook)
2069220178Sobrien		el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN);
2070220220Sobrien	return (int)num_read;
2071220178Sobrien}
2072220178Sobrien
2073220178Sobrienstatic void
2074220178Sobrien_rl_update_pos(void)
2075220178Sobrien{
2076220178Sobrien	const LineInfo *li = el_line(e);
2077220178Sobrien
2078220220Sobrien	rl_point = (int)(li->cursor - li->buffer);
2079220220Sobrien	rl_end = (int)(li->lastchar - li->buffer);
2080220178Sobrien}
2081220218Sobrien
2082220218Sobrienvoid
2083220218Sobrienrl_get_screen_size(int *rows, int *cols)
2084220218Sobrien{
2085220218Sobrien	if (rows)
2086220218Sobrien		el_get(e, EL_GETTC, "li", rows);
2087220218Sobrien	if (cols)
2088220218Sobrien		el_get(e, EL_GETTC, "co", cols);
2089220218Sobrien}
2090220218Sobrien
2091220218Sobrienvoid
2092220218Sobrienrl_set_screen_size(int rows, int cols)
2093220218Sobrien{
2094220218Sobrien	char buf[64];
2095220218Sobrien	(void)snprintf(buf, sizeof(buf), "%d", rows);
2096220218Sobrien	el_set(e, EL_SETTC, "li", buf);
2097220218Sobrien	(void)snprintf(buf, sizeof(buf), "%d", cols);
2098220218Sobrien	el_set(e, EL_SETTC, "co", buf);
2099220218Sobrien}
2100220218Sobrien
2101220220Sobrienchar **
2102220220Sobrienrl_completion_matches(const char *str, rl_compentry_func_t *fun)
2103220220Sobrien{
2104220220Sobrien	size_t len, max, i, j, min;
2105220220Sobrien	char **list, *match, *a, *b;
2106220220Sobrien
2107220220Sobrien	len = 1;
2108220220Sobrien	max = 10;
2109220220Sobrien	if ((list = malloc(max * sizeof(*list))) == NULL)
2110220220Sobrien		return NULL;
2111220220Sobrien
2112220220Sobrien	while ((match = (*fun)(str, (int)(len - 1))) != NULL) {
2113220220Sobrien		list[len++] = match;
2114220220Sobrien		if (len == max) {
2115220220Sobrien			char **nl;
2116220220Sobrien			max += 10;
2117220220Sobrien			if ((nl = realloc(list, max * sizeof(*nl))) == NULL)
2118220220Sobrien				goto out;
2119220220Sobrien			list = nl;
2120220220Sobrien		}
2121220220Sobrien	}
2122220220Sobrien	if (len == 1)
2123220220Sobrien		goto out;
2124220220Sobrien	list[len] = NULL;
2125220220Sobrien	if (len == 2) {
2126220220Sobrien		if ((list[0] = strdup(list[1])) == NULL)
2127220220Sobrien			goto out;
2128220220Sobrien		return list;
2129220220Sobrien	}
2130220220Sobrien	qsort(&list[1], len - 1, sizeof(*list),
2131220220Sobrien	    (int (*)(const void *, const void *)) strcmp);
2132220220Sobrien	min = SIZE_T_MAX;
2133220220Sobrien	for (i = 1, a = list[i]; i < len - 1; i++, a = b) {
2134220220Sobrien		b = list[i + 1];
2135220220Sobrien		for (j = 0; a[j] && a[j] == b[j]; j++)
2136220220Sobrien			continue;
2137220220Sobrien		if (min > j)
2138220220Sobrien			min = j;
2139220220Sobrien	}
2140220220Sobrien	if (min == 0 && *str) {
2141220220Sobrien		if ((list[0] = strdup(str)) == NULL)
2142220220Sobrien			goto out;
2143220220Sobrien	} else {
2144220220Sobrien		if ((list[0] = malloc(min + 1)) == NULL)
2145220220Sobrien			goto out;
2146220220Sobrien		(void)memcpy(list[0], list[1], min);
2147220220Sobrien		list[0][min] = '\0';
2148220220Sobrien	}
2149220220Sobrien	return list;
2150220220Sobrien
2151220220Sobrienout:
2152220220Sobrien	free(list);
2153220220Sobrien	return NULL;
2154220220Sobrien}
2155220220Sobrien
2156220218Sobrienchar *
2157220218Sobrienrl_filename_completion_function (const char *text, int state)
2158220218Sobrien{
2159220218Sobrien	return fn_filename_completion_function(text, state);
2160220218Sobrien}
2161220218Sobrien
2162220220Sobrienvoid
2163220220Sobrienrl_forced_update_display(void)
2164220220Sobrien{
2165220220Sobrien	el_set(e, EL_REFRESH);
2166220220Sobrien}
2167220220Sobrien
2168220218Sobrienint
2169220218Sobrien_rl_abort_internal(void)
2170220218Sobrien{
2171220218Sobrien	el_beep(e);
2172220218Sobrien	longjmp(topbuf, 1);
2173220218Sobrien	/*NOTREACHED*/
2174220218Sobrien}
2175220218Sobrien
2176220218Sobrienint
2177220218Sobrien_rl_qsort_string_compare(char **s1, char **s2)
2178220218Sobrien{
2179220218Sobrien	return strcoll(*s1, *s2);
2180220218Sobrien}
2181220218Sobrien
2182220220SobrienHISTORY_STATE *
2183220220Sobrienhistory_get_history_state(void)
2184220220Sobrien{
2185220220Sobrien	HISTORY_STATE *hs;
2186220220Sobrien
2187220220Sobrien	if ((hs = malloc(sizeof(HISTORY_STATE))) == NULL)
2188220220Sobrien		return (NULL);
2189220220Sobrien	hs->length = history_length;
2190220220Sobrien	return (hs);
2191220220Sobrien}
2192220220Sobrien
2193220218Sobrienint
2194220218Sobrien/*ARGSUSED*/
2195220218Sobrienrl_kill_text(int from, int to)
2196220218Sobrien{
2197220218Sobrien	return 0;
2198220218Sobrien}
2199220218Sobrien
2200220218SobrienKeymap
2201220218Sobrienrl_make_bare_keymap(void)
2202220218Sobrien{
2203220218Sobrien	return NULL;
2204220218Sobrien}
2205220218Sobrien
2206220218SobrienKeymap
2207220218Sobrienrl_get_keymap(void)
2208220218Sobrien{
2209220218Sobrien	return NULL;
2210220218Sobrien}
2211220218Sobrien
2212220218Sobrienvoid
2213220218Sobrien/*ARGSUSED*/
2214220218Sobrienrl_set_keymap(Keymap k)
2215220218Sobrien{
2216220218Sobrien}
2217220218Sobrien
2218220218Sobrienint
2219220218Sobrien/*ARGSUSED*/
2220220218Sobrienrl_generic_bind(int type, const char * keyseq, const char * data, Keymap k)
2221220218Sobrien{
2222220218Sobrien	return 0;
2223220218Sobrien}
2224220218Sobrien
2225220218Sobrienint
2226220218Sobrien/*ARGSUSED*/
2227220220Sobrienrl_bind_key_in_map(int key, rl_command_func_t *fun, Keymap k)
2228220218Sobrien{
2229220218Sobrien	return 0;
2230220218Sobrien}
2231220218Sobrien
2232220220Sobrien/* unsupported, but needed by python */
2233220220Sobrienvoid
2234220220Sobrienrl_cleanup_after_signal(void)
2235220220Sobrien{
2236220220Sobrien}
2237220329Sobrien
2238220329Sobrienint
2239220329Sobrienrl_on_new_line(void)
2240220329Sobrien{
2241220329Sobrien	return 0;
2242220329Sobrien}
2243