xref: /freebsd/contrib/ntp/libntp/ntp_lineedit.c (revision 5b9c547c)
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 
39 extern char *	progname;
40 
41 /*
42  * globals, private prototypes
43  */
44 
45 static int	ntp_readline_initted;
46 static char *	lineedit_prompt;
47 
48 
49 #ifdef LE_EDITLINE
50 # ifndef H_SETSIZE
51 #  define H_SETSIZE H_EVENT
52 # endif
53 static EditLine *	ntp_el;
54 static History *	ntp_hist;
55 static HistEvent	hev;
56 
57 char *	ntp_prompt_callback(EditLine *);
58 #endif	/* LE_EDITLINE */
59 
60 
61 /*
62  * ntp_readline_init - setup, set or reset prompt string
63  */
64 int
65 ntp_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  */
128 void
129 ntp_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 
158 char *
159 ntp_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  */
235 char *
236 ntp_prompt_callback(
237 	EditLine *el
238 	)
239 {
240 	UNUSED_ARG(el);
241 
242 	return lineedit_prompt;
243 }
244 #endif /* LE_EDITLINE */
245 
246