xref: /netbsd-src/external/bsd/ntp/dist/libntp/ntp_lineedit.c (revision cdfa2a7ef92791ba9db70a584a1d904730e6fb46)
1*cdfa2a7eSchristos /*	$NetBSD: ntp_lineedit.c,v 1.10 2020/05/25 20:47:24 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * ntp_lineedit.c - generic interface to various line editing libs
5abb0f93cSkardel  */
6abb0f93cSkardel #ifdef HAVE_CONFIG_H
7abb0f93cSkardel # include <config.h>
8abb0f93cSkardel #endif
9abb0f93cSkardel 
10abb0f93cSkardel #include <errno.h>
11abb0f93cSkardel #include <string.h>
12abb0f93cSkardel #include <stdlib.h>
13abb0f93cSkardel #include <stdio.h>
14abb0f93cSkardel 
153123f114Skardel #if defined(HAVE_READLINE_HISTORY) &&		\
163123f114Skardel     (!defined(HAVE_READLINE_HISTORY_H) ||	\
173123f114Skardel      !defined(HAVE_READLINE_READLINE_H))
183123f114Skardel # undef HAVE_READLINE_HISTORY
193123f114Skardel #endif
20abb0f93cSkardel #if defined(HAVE_READLINE_HISTORY)
21abb0f93cSkardel # include <readline/readline.h>
22abb0f93cSkardel # include <readline/history.h>
233123f114Skardel # define LE_READLINE
243123f114Skardel #elif defined(HAVE_HISTEDIT_H)
25abb0f93cSkardel # include <histedit.h>
263123f114Skardel # define LE_EDITLINE
273123f114Skardel #else
283123f114Skardel # define LE_NONE
29abb0f93cSkardel #endif
30abb0f93cSkardel 
31abb0f93cSkardel #include "ntp.h"
32abb0f93cSkardel #include "ntp_stdlib.h"
33abb0f93cSkardel #include "ntp_lineedit.h"
348b8da087Schristos #include "safecast.h"
35abb0f93cSkardel 
36abb0f93cSkardel #define MAXEDITLINE	512
37abb0f93cSkardel 
38abb0f93cSkardel /*
39abb0f93cSkardel  * external references
40abb0f93cSkardel  */
41abb0f93cSkardel 
42af12ab5eSchristos extern char const *	progname;
43abb0f93cSkardel 
44abb0f93cSkardel /*
45abb0f93cSkardel  * globals, private prototypes
46abb0f93cSkardel  */
47abb0f93cSkardel 
48abb0f93cSkardel static int	ntp_readline_initted;
49abb0f93cSkardel static char *	lineedit_prompt;
50abb0f93cSkardel 
51abb0f93cSkardel 
523123f114Skardel #ifdef LE_EDITLINE
533123f114Skardel # ifndef H_SETSIZE
543123f114Skardel #  define H_SETSIZE H_EVENT
553123f114Skardel # endif
56abb0f93cSkardel static EditLine *	ntp_el;
57abb0f93cSkardel static History *	ntp_hist;
58abb0f93cSkardel static HistEvent	hev;
59abb0f93cSkardel 
60abb0f93cSkardel char *	ntp_prompt_callback(EditLine *);
613123f114Skardel #endif	/* LE_EDITLINE */
62abb0f93cSkardel 
63abb0f93cSkardel 
64abb0f93cSkardel /*
65abb0f93cSkardel  * ntp_readline_init - setup, set or reset prompt string
66abb0f93cSkardel  */
67abb0f93cSkardel int
ntp_readline_init(const char * prompt)68abb0f93cSkardel ntp_readline_init(
69abb0f93cSkardel 	const char *	prompt
70abb0f93cSkardel 	)
71abb0f93cSkardel {
72abb0f93cSkardel 	int	success;
73abb0f93cSkardel 
74abb0f93cSkardel 	success = 1;
75abb0f93cSkardel 
76abb0f93cSkardel 	if (prompt) {
77abb0f93cSkardel 		if (lineedit_prompt)
78abb0f93cSkardel 			free(lineedit_prompt);
79abb0f93cSkardel 		lineedit_prompt = estrdup(prompt);
80abb0f93cSkardel 	}
81abb0f93cSkardel 
823123f114Skardel #ifdef LE_EDITLINE
83abb0f93cSkardel 	if (NULL == ntp_el) {
84abb0f93cSkardel 
853123f114Skardel # if 4 == EL_INIT_ARGS
86abb0f93cSkardel 		ntp_el = el_init(progname, stdin, stdout, stderr);
873123f114Skardel # else
883123f114Skardel 		ntp_el = el_init(progname, stdin, stdout);
893123f114Skardel # endif
90abb0f93cSkardel 		if (ntp_el) {
91abb0f93cSkardel 
92abb0f93cSkardel 			el_set(ntp_el, EL_PROMPT, ntp_prompt_callback);
93abb0f93cSkardel 			el_set(ntp_el, EL_EDITOR, "emacs");
94abb0f93cSkardel 
95abb0f93cSkardel 			ntp_hist = history_init();
96abb0f93cSkardel 
97abb0f93cSkardel 			if (NULL == ntp_hist) {
98abb0f93cSkardel 
992950cc38Schristos 				mfprintf(stderr, "history_init(): %m\n");
100abb0f93cSkardel 				fflush(stderr);
101abb0f93cSkardel 
102abb0f93cSkardel 				el_end(ntp_el);
103abb0f93cSkardel 				ntp_el = NULL;
104abb0f93cSkardel 
105abb0f93cSkardel 				success = 0;
106abb0f93cSkardel 
107abb0f93cSkardel 			} else {
1082950cc38Schristos 				ZERO(hev);
1093123f114Skardel #ifdef H_SETSIZE
110abb0f93cSkardel 				history(ntp_hist, &hev, H_SETSIZE, 128);
1113123f114Skardel #endif
1123123f114Skardel 				el_set(ntp_el, EL_HIST, history,
1133123f114Skardel 				       ntp_hist);
114abb0f93cSkardel 				/* use any .editrc */
115abb0f93cSkardel 				el_source(ntp_el, NULL);
116abb0f93cSkardel 			}
117abb0f93cSkardel 		} else
118abb0f93cSkardel 			success = 0;
119abb0f93cSkardel 	}
1203123f114Skardel #endif	/* LE_EDITLINE */
121abb0f93cSkardel 
122abb0f93cSkardel 	ntp_readline_initted = success;
123abb0f93cSkardel 
124abb0f93cSkardel 	return success;
125abb0f93cSkardel }
126abb0f93cSkardel 
127abb0f93cSkardel 
128abb0f93cSkardel /*
129abb0f93cSkardel  * ntp_readline_uninit - release resources
130abb0f93cSkardel  */
131abb0f93cSkardel void
ntp_readline_uninit(void)132abb0f93cSkardel ntp_readline_uninit(
133abb0f93cSkardel 	void
134abb0f93cSkardel 	)
135abb0f93cSkardel {
1363123f114Skardel #ifdef LE_EDITLINE
137abb0f93cSkardel 	if (ntp_el) {
138abb0f93cSkardel 		el_end(ntp_el);
139abb0f93cSkardel 		ntp_el = NULL;
140abb0f93cSkardel 
141abb0f93cSkardel 		history_end(ntp_hist);
142abb0f93cSkardel 		ntp_hist = NULL;
143abb0f93cSkardel 	}
1443123f114Skardel #endif	/* LE_EDITLINE */
145abb0f93cSkardel 
146abb0f93cSkardel 	if (lineedit_prompt) {
147abb0f93cSkardel 		free(lineedit_prompt);
148abb0f93cSkardel 		lineedit_prompt = NULL;
149abb0f93cSkardel 	}
150abb0f93cSkardel 
151abb0f93cSkardel 	ntp_readline_initted = 0;
152abb0f93cSkardel }
153abb0f93cSkardel 
154abb0f93cSkardel 
155abb0f93cSkardel /*
156abb0f93cSkardel  * ntp_readline - read a line with the line editor available
157abb0f93cSkardel  *
158abb0f93cSkardel  * The string returned must be released with free()
159abb0f93cSkardel  */
160abb0f93cSkardel 
161abb0f93cSkardel char *
ntp_readline(int * pcount)162abb0f93cSkardel ntp_readline(
163abb0f93cSkardel 	int *	pcount
164abb0f93cSkardel 	)
165abb0f93cSkardel {
1663123f114Skardel 	char *		line;
1673123f114Skardel #ifdef LE_NONE
168abb0f93cSkardel 	char		line_buf[MAXEDITLINE];
169abb0f93cSkardel #endif
1703123f114Skardel #ifdef LE_EDITLINE
171abb0f93cSkardel 	const char *	cline;
172abb0f93cSkardel #endif
173abb0f93cSkardel 
174abb0f93cSkardel 	if (!ntp_readline_initted)
175abb0f93cSkardel 		return NULL;
176abb0f93cSkardel 
177abb0f93cSkardel 	*pcount = 0;
178abb0f93cSkardel 
1793123f114Skardel #ifdef LE_READLINE
180abb0f93cSkardel 	line = readline(lineedit_prompt ? lineedit_prompt : "");
181abb0f93cSkardel 	if (NULL != line) {
182abb0f93cSkardel 		if (*line) {
183abb0f93cSkardel 			add_history(line);
184abb0f93cSkardel 		}
18527340923Skardel 		*pcount = strlen(line);
186abb0f93cSkardel 	}
1873123f114Skardel #endif	/* LE_READLINE */
188abb0f93cSkardel 
1893123f114Skardel #ifdef LE_EDITLINE
190abb0f93cSkardel 	cline = el_gets(ntp_el, pcount);
191abb0f93cSkardel 
19227340923Skardel 	if (NULL != cline) {
193abb0f93cSkardel 		history(ntp_hist, &hev, H_ENTER, cline);
194abb0f93cSkardel 		line = estrdup(cline);
19527340923Skardel 	} else if (*pcount == -1) {
196abb0f93cSkardel 		line = NULL;
19727340923Skardel 	} else {
19827340923Skardel 		line = estrdup("");
19927340923Skardel 	}
2003123f114Skardel #endif	/* LE_EDITLINE */
201abb0f93cSkardel 
2023123f114Skardel #ifdef LE_NONE
203abb0f93cSkardel 					/* stone hammers */
204abb0f93cSkardel 	if (lineedit_prompt) {
205abb0f93cSkardel # ifdef VMS
206abb0f93cSkardel 			/*
207abb0f93cSkardel 			 * work around problem mixing
208abb0f93cSkardel 			 * stdout & stderr
209abb0f93cSkardel 			 */
210abb0f93cSkardel 			fputs("", stdout);
211abb0f93cSkardel # endif	/* VMS */
212abb0f93cSkardel 
213abb0f93cSkardel 		fputs(lineedit_prompt, stderr);
214abb0f93cSkardel 		fflush(stderr);
215abb0f93cSkardel 	}
216abb0f93cSkardel 
217abb0f93cSkardel 	line = fgets(line_buf, sizeof(line_buf), stdin);
218abb0f93cSkardel 	if (NULL != line && *line) {
2198b8da087Schristos 		*pcount = (int)strlen(line); /* cannot overflow here */
220abb0f93cSkardel 		line = estrdup(line);
221abb0f93cSkardel 	} else
222abb0f93cSkardel 		line = NULL;
223abb0f93cSkardel 
2243123f114Skardel #endif	/* LE_NONE */
225abb0f93cSkardel 
226abb0f93cSkardel 
227abb0f93cSkardel 	if (!line)			/* EOF */
228abb0f93cSkardel 		fputs("\n", stderr);
229abb0f93cSkardel 
230abb0f93cSkardel 	return line;
231abb0f93cSkardel }
232abb0f93cSkardel 
233abb0f93cSkardel 
2343123f114Skardel #ifdef LE_EDITLINE
235abb0f93cSkardel /*
236abb0f93cSkardel  * ntp_prompt_callback - return prompt string to el_gets()
237abb0f93cSkardel  */
238abb0f93cSkardel char *
ntp_prompt_callback(EditLine * el)239abb0f93cSkardel ntp_prompt_callback(
240abb0f93cSkardel 	EditLine *el
241abb0f93cSkardel 	)
242abb0f93cSkardel {
243abb0f93cSkardel 	UNUSED_ARG(el);
244abb0f93cSkardel 
245abb0f93cSkardel 	return lineedit_prompt;
246abb0f93cSkardel }
2473123f114Skardel #endif /* LE_EDITLINE */
248abb0f93cSkardel 
249