1/*
2 * ntp_lineedit.c - generic interface to various line editing libs
3 */
4#ifdef HAVE_CONFIG_H
5# include <config.h>
6#endif
7
8#include <errno.h>
9#include <string.h>
10#include <stdlib.h>
11#include <stdio.h>
12
13#if defined(HAVE_READLINE_HISTORY) &&		\
14    (!defined(HAVE_READLINE_HISTORY_H) ||	\
15     !defined(HAVE_READLINE_READLINE_H))
16# undef HAVE_READLINE_HISTORY
17#endif
18#if defined(HAVE_READLINE_HISTORY)
19# include <readline/readline.h>
20# include <readline/history.h>
21# define LE_READLINE
22#elif defined(HAVE_HISTEDIT_H)
23# include <histedit.h>
24# define LE_EDITLINE
25#else
26# define LE_NONE
27#endif
28
29#include "ntp.h"
30#include "ntp_stdlib.h"
31#include "ntp_lineedit.h"
32#include "safecast.h"
33
34#define MAXEDITLINE	512
35
36/*
37 * external references
38 */
39
40extern char const *	progname;
41
42/*
43 * globals, private prototypes
44 */
45
46static int	ntp_readline_initted;
47static char *	lineedit_prompt;
48
49
50#ifdef LE_EDITLINE
51# ifndef H_SETSIZE
52#  define H_SETSIZE H_EVENT
53# endif
54static EditLine *	ntp_el;
55static History *	ntp_hist;
56static HistEvent	hev;
57
58char *	ntp_prompt_callback(EditLine *);
59#endif	/* LE_EDITLINE */
60
61
62/*
63 * ntp_readline_init - setup, set or reset prompt string
64 */
65int
66ntp_readline_init(
67	const char *	prompt
68	)
69{
70	int	success;
71
72	success = 1;
73
74	if (prompt) {
75		if (lineedit_prompt)
76			free(lineedit_prompt);
77		lineedit_prompt = estrdup(prompt);
78	}
79
80#ifdef LE_EDITLINE
81	if (NULL == ntp_el) {
82
83# if 4 == EL_INIT_ARGS
84		ntp_el = el_init(progname, stdin, stdout, stderr);
85# else
86		ntp_el = el_init(progname, stdin, stdout);
87# endif
88		if (ntp_el) {
89
90			el_set(ntp_el, EL_PROMPT, ntp_prompt_callback);
91			el_set(ntp_el, EL_EDITOR, "emacs");
92
93			ntp_hist = history_init();
94
95			if (NULL == ntp_hist) {
96
97				mfprintf(stderr, "history_init(): %m\n");
98				fflush(stderr);
99
100				el_end(ntp_el);
101				ntp_el = NULL;
102
103				success = 0;
104
105			} else {
106				ZERO(hev);
107#ifdef H_SETSIZE
108				history(ntp_hist, &hev, H_SETSIZE, 128);
109#endif
110				el_set(ntp_el, EL_HIST, history,
111				       ntp_hist);
112				/* use any .editrc */
113				el_source(ntp_el, NULL);
114			}
115		} else
116			success = 0;
117	}
118#endif	/* LE_EDITLINE */
119
120	ntp_readline_initted = success;
121
122	return success;
123}
124
125
126/*
127 * ntp_readline_uninit - release resources
128 */
129void
130ntp_readline_uninit(
131	void
132	)
133{
134#ifdef LE_EDITLINE
135	if (ntp_el) {
136		el_end(ntp_el);
137		ntp_el = NULL;
138
139		history_end(ntp_hist);
140		ntp_hist = NULL;
141	}
142#endif	/* LE_EDITLINE */
143
144	if (lineedit_prompt) {
145		free(lineedit_prompt);
146		lineedit_prompt = NULL;
147	}
148
149	ntp_readline_initted = 0;
150}
151
152
153/*
154 * ntp_readline - read a line with the line editor available
155 *
156 * The string returned must be released with free()
157 */
158
159char *
160ntp_readline(
161	int *	pcount
162	)
163{
164	char *		line;
165#ifdef LE_NONE
166	char		line_buf[MAXEDITLINE];
167#endif
168#ifdef LE_EDITLINE
169	const char *	cline;
170#endif
171
172	if (!ntp_readline_initted)
173		return NULL;
174
175	*pcount = 0;
176
177#ifdef LE_READLINE
178	line = readline(lineedit_prompt ? lineedit_prompt : "");
179	if (NULL != line) {
180		if (*line) {
181			add_history(line);
182		}
183		*pcount = strlen(line);
184	}
185#endif	/* LE_READLINE */
186
187#ifdef LE_EDITLINE
188	cline = el_gets(ntp_el, pcount);
189
190	if (NULL != cline) {
191		history(ntp_hist, &hev, H_ENTER, cline);
192		line = estrdup(cline);
193	} else if (*pcount == -1) {
194		line = NULL;
195	} else {
196		line = estrdup("");
197	}
198#endif	/* LE_EDITLINE */
199
200#ifdef LE_NONE
201					/* stone hammers */
202	if (lineedit_prompt) {
203# ifdef VMS
204			/*
205			 * work around problem mixing
206			 * stdout & stderr
207			 */
208			fputs("", stdout);
209# endif	/* VMS */
210
211		fputs(lineedit_prompt, stderr);
212		fflush(stderr);
213	}
214
215	line = fgets(line_buf, sizeof(line_buf), stdin);
216	if (NULL != line && *line) {
217		*pcount = (int)strlen(line); /* cannot overflow here */
218		line = estrdup(line);
219	} else
220		line = NULL;
221
222#endif	/* LE_NONE */
223
224
225	if (!line)			/* EOF */
226		fputs("\n", stderr);
227
228	return line;
229}
230
231
232#ifdef LE_EDITLINE
233/*
234 * ntp_prompt_callback - return prompt string to el_gets()
235 */
236char *
237ntp_prompt_callback(
238	EditLine *el
239	)
240{
241	UNUSED_ARG(el);
242
243	return lineedit_prompt;
244}
245#endif /* LE_EDITLINE */
246
247