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