1258945Sroberto/*
2258945Sroberto * ntp_lineedit.c - generic interface to various line editing libs
3258945Sroberto */
4258945Sroberto#ifdef HAVE_CONFIG_H
5258945Sroberto# include <config.h>
6258945Sroberto#endif
7258945Sroberto
8258945Sroberto#include <errno.h>
9258945Sroberto#include <string.h>
10258945Sroberto#include <stdlib.h>
11258945Sroberto#include <stdio.h>
12258945Sroberto
13258945Sroberto#if defined(HAVE_READLINE_HISTORY) &&		\
14258945Sroberto    (!defined(HAVE_READLINE_HISTORY_H) ||	\
15258945Sroberto     !defined(HAVE_READLINE_READLINE_H))
16258945Sroberto# undef HAVE_READLINE_HISTORY
17258945Sroberto#endif
18258945Sroberto#if defined(HAVE_READLINE_HISTORY)
19258945Sroberto# include <readline/readline.h>
20258945Sroberto# include <readline/history.h>
21258945Sroberto# define LE_READLINE
22258945Sroberto#elif defined(HAVE_HISTEDIT_H)
23258945Sroberto# include <histedit.h>
24258945Sroberto# define LE_EDITLINE
25258945Sroberto#else
26258945Sroberto# define LE_NONE
27258945Sroberto#endif
28258945Sroberto
29258945Sroberto#include "ntp.h"
30258945Sroberto#include "ntp_stdlib.h"
31258945Sroberto#include "ntp_lineedit.h"
32293423Sdelphij#include "safecast.h"
33258945Sroberto
34258945Sroberto#define MAXEDITLINE	512
35258945Sroberto
36258945Sroberto/*
37258945Sroberto * external references
38258945Sroberto */
39258945Sroberto
40289764Sglebiusextern char const *	progname;
41258945Sroberto
42258945Sroberto/*
43258945Sroberto * globals, private prototypes
44258945Sroberto */
45258945Sroberto
46258945Srobertostatic int	ntp_readline_initted;
47258945Srobertostatic char *	lineedit_prompt;
48258945Sroberto
49258945Sroberto
50258945Sroberto#ifdef LE_EDITLINE
51258945Sroberto# ifndef H_SETSIZE
52258945Sroberto#  define H_SETSIZE H_EVENT
53258945Sroberto# endif
54258945Srobertostatic EditLine *	ntp_el;
55258945Srobertostatic History *	ntp_hist;
56258945Srobertostatic HistEvent	hev;
57258945Sroberto
58258945Srobertochar *	ntp_prompt_callback(EditLine *);
59258945Sroberto#endif	/* LE_EDITLINE */
60258945Sroberto
61258945Sroberto
62258945Sroberto/*
63258945Sroberto * ntp_readline_init - setup, set or reset prompt string
64258945Sroberto */
65258945Srobertoint
66258945Srobertontp_readline_init(
67258945Sroberto	const char *	prompt
68258945Sroberto	)
69258945Sroberto{
70258945Sroberto	int	success;
71258945Sroberto
72258945Sroberto	success = 1;
73258945Sroberto
74258945Sroberto	if (prompt) {
75258945Sroberto		if (lineedit_prompt)
76258945Sroberto			free(lineedit_prompt);
77258945Sroberto		lineedit_prompt = estrdup(prompt);
78258945Sroberto	}
79258945Sroberto
80258945Sroberto#ifdef LE_EDITLINE
81258945Sroberto	if (NULL == ntp_el) {
82258945Sroberto
83258945Sroberto# if 4 == EL_INIT_ARGS
84258945Sroberto		ntp_el = el_init(progname, stdin, stdout, stderr);
85258945Sroberto# else
86258945Sroberto		ntp_el = el_init(progname, stdin, stdout);
87258945Sroberto# endif
88258945Sroberto		if (ntp_el) {
89258945Sroberto
90258945Sroberto			el_set(ntp_el, EL_PROMPT, ntp_prompt_callback);
91258945Sroberto			el_set(ntp_el, EL_EDITOR, "emacs");
92258945Sroberto
93258945Sroberto			ntp_hist = history_init();
94258945Sroberto
95258945Sroberto			if (NULL == ntp_hist) {
96258945Sroberto
97280849Scy				mfprintf(stderr, "history_init(): %m\n");
98258945Sroberto				fflush(stderr);
99258945Sroberto
100258945Sroberto				el_end(ntp_el);
101258945Sroberto				ntp_el = NULL;
102258945Sroberto
103258945Sroberto				success = 0;
104258945Sroberto
105258945Sroberto			} else {
106280849Scy				ZERO(hev);
107258945Sroberto#ifdef H_SETSIZE
108258945Sroberto				history(ntp_hist, &hev, H_SETSIZE, 128);
109258945Sroberto#endif
110258945Sroberto				el_set(ntp_el, EL_HIST, history,
111258945Sroberto				       ntp_hist);
112258945Sroberto				/* use any .editrc */
113258945Sroberto				el_source(ntp_el, NULL);
114258945Sroberto			}
115258945Sroberto		} else
116258945Sroberto			success = 0;
117258945Sroberto	}
118258945Sroberto#endif	/* LE_EDITLINE */
119258945Sroberto
120258945Sroberto	ntp_readline_initted = success;
121258945Sroberto
122258945Sroberto	return success;
123258945Sroberto}
124258945Sroberto
125258945Sroberto
126258945Sroberto/*
127258945Sroberto * ntp_readline_uninit - release resources
128258945Sroberto */
129258945Srobertovoid
130258945Srobertontp_readline_uninit(
131258945Sroberto	void
132258945Sroberto	)
133258945Sroberto{
134258945Sroberto#ifdef LE_EDITLINE
135258945Sroberto	if (ntp_el) {
136258945Sroberto		el_end(ntp_el);
137258945Sroberto		ntp_el = NULL;
138258945Sroberto
139258945Sroberto		history_end(ntp_hist);
140258945Sroberto		ntp_hist = NULL;
141258945Sroberto	}
142258945Sroberto#endif	/* LE_EDITLINE */
143258945Sroberto
144258945Sroberto	if (lineedit_prompt) {
145258945Sroberto		free(lineedit_prompt);
146258945Sroberto		lineedit_prompt = NULL;
147258945Sroberto	}
148258945Sroberto
149258945Sroberto	ntp_readline_initted = 0;
150258945Sroberto}
151258945Sroberto
152258945Sroberto
153258945Sroberto/*
154258945Sroberto * ntp_readline - read a line with the line editor available
155258945Sroberto *
156258945Sroberto * The string returned must be released with free()
157258945Sroberto */
158258945Sroberto
159258945Srobertochar *
160258945Srobertontp_readline(
161258945Sroberto	int *	pcount
162258945Sroberto	)
163258945Sroberto{
164258945Sroberto	char *		line;
165258945Sroberto#ifdef LE_NONE
166258945Sroberto	char		line_buf[MAXEDITLINE];
167258945Sroberto#endif
168258945Sroberto#ifdef LE_EDITLINE
169258945Sroberto	const char *	cline;
170258945Sroberto#endif
171258945Sroberto
172258945Sroberto	if (!ntp_readline_initted)
173258945Sroberto		return NULL;
174258945Sroberto
175258945Sroberto	*pcount = 0;
176258945Sroberto
177258945Sroberto#ifdef LE_READLINE
178258945Sroberto	line = readline(lineedit_prompt ? lineedit_prompt : "");
179258945Sroberto	if (NULL != line) {
180258945Sroberto		if (*line) {
181258945Sroberto			add_history(line);
182258945Sroberto		}
183280849Scy		*pcount = strlen(line);
184258945Sroberto	}
185258945Sroberto#endif	/* LE_READLINE */
186258945Sroberto
187258945Sroberto#ifdef LE_EDITLINE
188258945Sroberto	cline = el_gets(ntp_el, pcount);
189258945Sroberto
190280849Scy	if (NULL != cline) {
191258945Sroberto		history(ntp_hist, &hev, H_ENTER, cline);
192258945Sroberto		line = estrdup(cline);
193280849Scy	} else if (*pcount == -1) {
194258945Sroberto		line = NULL;
195280849Scy	} else {
196280849Scy		line = estrdup("");
197280849Scy	}
198258945Sroberto#endif	/* LE_EDITLINE */
199258945Sroberto
200258945Sroberto#ifdef LE_NONE
201258945Sroberto					/* stone hammers */
202258945Sroberto	if (lineedit_prompt) {
203258945Sroberto# ifdef VMS
204258945Sroberto			/*
205258945Sroberto			 * work around problem mixing
206258945Sroberto			 * stdout & stderr
207258945Sroberto			 */
208258945Sroberto			fputs("", stdout);
209258945Sroberto# endif	/* VMS */
210258945Sroberto
211258945Sroberto		fputs(lineedit_prompt, stderr);
212258945Sroberto		fflush(stderr);
213258945Sroberto	}
214258945Sroberto
215258945Sroberto	line = fgets(line_buf, sizeof(line_buf), stdin);
216258945Sroberto	if (NULL != line && *line) {
217293423Sdelphij		*pcount = (int)strlen(line); /* cannot overflow here */
218258945Sroberto		line = estrdup(line);
219258945Sroberto	} else
220258945Sroberto		line = NULL;
221258945Sroberto
222258945Sroberto#endif	/* LE_NONE */
223258945Sroberto
224258945Sroberto
225258945Sroberto	if (!line)			/* EOF */
226258945Sroberto		fputs("\n", stderr);
227258945Sroberto
228258945Sroberto	return line;
229258945Sroberto}
230258945Sroberto
231258945Sroberto
232258945Sroberto#ifdef LE_EDITLINE
233258945Sroberto/*
234258945Sroberto * ntp_prompt_callback - return prompt string to el_gets()
235258945Sroberto */
236258945Srobertochar *
237258945Srobertontp_prompt_callback(
238258945Sroberto	EditLine *el
239258945Sroberto	)
240258945Sroberto{
241258945Sroberto	UNUSED_ARG(el);
242258945Sroberto
243258945Sroberto	return lineedit_prompt;
244258945Sroberto}
245258945Sroberto#endif /* LE_EDITLINE */
246258945Sroberto
247