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