xref: /freebsd/contrib/ntp/libntp/ntp_lineedit.c (revision 009e81b16465ea457c0e63fd49fe77f47cc27a5a)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * ntp_lineedit.c - generic interface to various line editing libs
32b15cb3dSCy Schubert  */
42b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H
52b15cb3dSCy Schubert # include <config.h>
62b15cb3dSCy Schubert #endif
72b15cb3dSCy Schubert 
82b15cb3dSCy Schubert #include <errno.h>
92b15cb3dSCy Schubert #include <string.h>
102b15cb3dSCy Schubert #include <stdlib.h>
112b15cb3dSCy Schubert #include <stdio.h>
122b15cb3dSCy Schubert 
132b15cb3dSCy Schubert #if defined(HAVE_READLINE_HISTORY) &&		\
142b15cb3dSCy Schubert     (!defined(HAVE_READLINE_HISTORY_H) ||	\
152b15cb3dSCy Schubert      !defined(HAVE_READLINE_READLINE_H))
162b15cb3dSCy Schubert # undef HAVE_READLINE_HISTORY
172b15cb3dSCy Schubert #endif
182b15cb3dSCy Schubert #if defined(HAVE_READLINE_HISTORY)
192b15cb3dSCy Schubert # include <readline/readline.h>
202b15cb3dSCy Schubert # include <readline/history.h>
212b15cb3dSCy Schubert # define LE_READLINE
222b15cb3dSCy Schubert #elif defined(HAVE_HISTEDIT_H)
232b15cb3dSCy Schubert # include <histedit.h>
242b15cb3dSCy Schubert # define LE_EDITLINE
252b15cb3dSCy Schubert #else
262b15cb3dSCy Schubert # define LE_NONE
272b15cb3dSCy Schubert #endif
282b15cb3dSCy Schubert 
292b15cb3dSCy Schubert #include "ntp.h"
302b15cb3dSCy Schubert #include "ntp_stdlib.h"
312b15cb3dSCy Schubert #include "ntp_lineedit.h"
32*3311ff84SXin LI #include "safecast.h"
332b15cb3dSCy Schubert 
342b15cb3dSCy Schubert #define MAXEDITLINE	512
352b15cb3dSCy Schubert 
362b15cb3dSCy Schubert /*
372b15cb3dSCy Schubert  * external references
382b15cb3dSCy Schubert  */
392b15cb3dSCy Schubert 
409034852cSGleb Smirnoff extern char const *	progname;
412b15cb3dSCy Schubert 
422b15cb3dSCy Schubert /*
432b15cb3dSCy Schubert  * globals, private prototypes
442b15cb3dSCy Schubert  */
452b15cb3dSCy Schubert 
462b15cb3dSCy Schubert static int	ntp_readline_initted;
472b15cb3dSCy Schubert static char *	lineedit_prompt;
482b15cb3dSCy Schubert 
492b15cb3dSCy Schubert 
502b15cb3dSCy Schubert #ifdef LE_EDITLINE
512b15cb3dSCy Schubert # ifndef H_SETSIZE
522b15cb3dSCy Schubert #  define H_SETSIZE H_EVENT
532b15cb3dSCy Schubert # endif
542b15cb3dSCy Schubert static EditLine *	ntp_el;
552b15cb3dSCy Schubert static History *	ntp_hist;
562b15cb3dSCy Schubert static HistEvent	hev;
572b15cb3dSCy Schubert 
582b15cb3dSCy Schubert char *	ntp_prompt_callback(EditLine *);
592b15cb3dSCy Schubert #endif	/* LE_EDITLINE */
602b15cb3dSCy Schubert 
612b15cb3dSCy Schubert 
622b15cb3dSCy Schubert /*
632b15cb3dSCy Schubert  * ntp_readline_init - setup, set or reset prompt string
642b15cb3dSCy Schubert  */
652b15cb3dSCy Schubert int
ntp_readline_init(const char * prompt)662b15cb3dSCy Schubert ntp_readline_init(
672b15cb3dSCy Schubert 	const char *	prompt
682b15cb3dSCy Schubert 	)
692b15cb3dSCy Schubert {
702b15cb3dSCy Schubert 	int	success;
712b15cb3dSCy Schubert 
722b15cb3dSCy Schubert 	success = 1;
732b15cb3dSCy Schubert 
742b15cb3dSCy Schubert 	if (prompt) {
752b15cb3dSCy Schubert 		if (lineedit_prompt)
762b15cb3dSCy Schubert 			free(lineedit_prompt);
772b15cb3dSCy Schubert 		lineedit_prompt = estrdup(prompt);
782b15cb3dSCy Schubert 	}
792b15cb3dSCy Schubert 
802b15cb3dSCy Schubert #ifdef LE_EDITLINE
812b15cb3dSCy Schubert 	if (NULL == ntp_el) {
822b15cb3dSCy Schubert 
832b15cb3dSCy Schubert # if 4 == EL_INIT_ARGS
842b15cb3dSCy Schubert 		ntp_el = el_init(progname, stdin, stdout, stderr);
852b15cb3dSCy Schubert # else
862b15cb3dSCy Schubert 		ntp_el = el_init(progname, stdin, stdout);
872b15cb3dSCy Schubert # endif
882b15cb3dSCy Schubert 		if (ntp_el) {
892b15cb3dSCy Schubert 
902b15cb3dSCy Schubert 			el_set(ntp_el, EL_PROMPT, ntp_prompt_callback);
912b15cb3dSCy Schubert 			el_set(ntp_el, EL_EDITOR, "emacs");
922b15cb3dSCy Schubert 
932b15cb3dSCy Schubert 			ntp_hist = history_init();
942b15cb3dSCy Schubert 
952b15cb3dSCy Schubert 			if (NULL == ntp_hist) {
962b15cb3dSCy Schubert 
972b15cb3dSCy Schubert 				mfprintf(stderr, "history_init(): %m\n");
982b15cb3dSCy Schubert 				fflush(stderr);
992b15cb3dSCy Schubert 
1002b15cb3dSCy Schubert 				el_end(ntp_el);
1012b15cb3dSCy Schubert 				ntp_el = NULL;
1022b15cb3dSCy Schubert 
1032b15cb3dSCy Schubert 				success = 0;
1042b15cb3dSCy Schubert 
1052b15cb3dSCy Schubert 			} else {
1062b15cb3dSCy Schubert 				ZERO(hev);
1072b15cb3dSCy Schubert #ifdef H_SETSIZE
1082b15cb3dSCy Schubert 				history(ntp_hist, &hev, H_SETSIZE, 128);
1092b15cb3dSCy Schubert #endif
1102b15cb3dSCy Schubert 				el_set(ntp_el, EL_HIST, history,
1112b15cb3dSCy Schubert 				       ntp_hist);
1122b15cb3dSCy Schubert 				/* use any .editrc */
1132b15cb3dSCy Schubert 				el_source(ntp_el, NULL);
1142b15cb3dSCy Schubert 			}
1152b15cb3dSCy Schubert 		} else
1162b15cb3dSCy Schubert 			success = 0;
1172b15cb3dSCy Schubert 	}
1182b15cb3dSCy Schubert #endif	/* LE_EDITLINE */
1192b15cb3dSCy Schubert 
1202b15cb3dSCy Schubert 	ntp_readline_initted = success;
1212b15cb3dSCy Schubert 
1222b15cb3dSCy Schubert 	return success;
1232b15cb3dSCy Schubert }
1242b15cb3dSCy Schubert 
1252b15cb3dSCy Schubert 
1262b15cb3dSCy Schubert /*
1272b15cb3dSCy Schubert  * ntp_readline_uninit - release resources
1282b15cb3dSCy Schubert  */
1292b15cb3dSCy Schubert void
ntp_readline_uninit(void)1302b15cb3dSCy Schubert ntp_readline_uninit(
1312b15cb3dSCy Schubert 	void
1322b15cb3dSCy Schubert 	)
1332b15cb3dSCy Schubert {
1342b15cb3dSCy Schubert #ifdef LE_EDITLINE
1352b15cb3dSCy Schubert 	if (ntp_el) {
1362b15cb3dSCy Schubert 		el_end(ntp_el);
1372b15cb3dSCy Schubert 		ntp_el = NULL;
1382b15cb3dSCy Schubert 
1392b15cb3dSCy Schubert 		history_end(ntp_hist);
1402b15cb3dSCy Schubert 		ntp_hist = NULL;
1412b15cb3dSCy Schubert 	}
1422b15cb3dSCy Schubert #endif	/* LE_EDITLINE */
1432b15cb3dSCy Schubert 
1442b15cb3dSCy Schubert 	if (lineedit_prompt) {
1452b15cb3dSCy Schubert 		free(lineedit_prompt);
1462b15cb3dSCy Schubert 		lineedit_prompt = NULL;
1472b15cb3dSCy Schubert 	}
1482b15cb3dSCy Schubert 
1492b15cb3dSCy Schubert 	ntp_readline_initted = 0;
1502b15cb3dSCy Schubert }
1512b15cb3dSCy Schubert 
1522b15cb3dSCy Schubert 
1532b15cb3dSCy Schubert /*
1542b15cb3dSCy Schubert  * ntp_readline - read a line with the line editor available
1552b15cb3dSCy Schubert  *
1562b15cb3dSCy Schubert  * The string returned must be released with free()
1572b15cb3dSCy Schubert  */
1582b15cb3dSCy Schubert 
1592b15cb3dSCy Schubert char *
ntp_readline(int * pcount)1602b15cb3dSCy Schubert ntp_readline(
1612b15cb3dSCy Schubert 	int *	pcount
1622b15cb3dSCy Schubert 	)
1632b15cb3dSCy Schubert {
1642b15cb3dSCy Schubert 	char *		line;
1652b15cb3dSCy Schubert #ifdef LE_NONE
1662b15cb3dSCy Schubert 	char		line_buf[MAXEDITLINE];
1672b15cb3dSCy Schubert #endif
1682b15cb3dSCy Schubert #ifdef LE_EDITLINE
1692b15cb3dSCy Schubert 	const char *	cline;
1702b15cb3dSCy Schubert #endif
1712b15cb3dSCy Schubert 
1722b15cb3dSCy Schubert 	if (!ntp_readline_initted)
1732b15cb3dSCy Schubert 		return NULL;
1742b15cb3dSCy Schubert 
1752b15cb3dSCy Schubert 	*pcount = 0;
1762b15cb3dSCy Schubert 
1772b15cb3dSCy Schubert #ifdef LE_READLINE
1782b15cb3dSCy Schubert 	line = readline(lineedit_prompt ? lineedit_prompt : "");
1792b15cb3dSCy Schubert 	if (NULL != line) {
1802b15cb3dSCy Schubert 		if (*line) {
1812b15cb3dSCy Schubert 			add_history(line);
1822b15cb3dSCy Schubert 		}
1832b15cb3dSCy Schubert 		*pcount = strlen(line);
1842b15cb3dSCy Schubert 	}
1852b15cb3dSCy Schubert #endif	/* LE_READLINE */
1862b15cb3dSCy Schubert 
1872b15cb3dSCy Schubert #ifdef LE_EDITLINE
1882b15cb3dSCy Schubert 	cline = el_gets(ntp_el, pcount);
1892b15cb3dSCy Schubert 
1902b15cb3dSCy Schubert 	if (NULL != cline) {
1912b15cb3dSCy Schubert 		history(ntp_hist, &hev, H_ENTER, cline);
1922b15cb3dSCy Schubert 		line = estrdup(cline);
1932b15cb3dSCy Schubert 	} else if (*pcount == -1) {
1942b15cb3dSCy Schubert 		line = NULL;
1952b15cb3dSCy Schubert 	} else {
1962b15cb3dSCy Schubert 		line = estrdup("");
1972b15cb3dSCy Schubert 	}
1982b15cb3dSCy Schubert #endif	/* LE_EDITLINE */
1992b15cb3dSCy Schubert 
2002b15cb3dSCy Schubert #ifdef LE_NONE
2012b15cb3dSCy Schubert 					/* stone hammers */
2022b15cb3dSCy Schubert 	if (lineedit_prompt) {
2032b15cb3dSCy Schubert # ifdef VMS
2042b15cb3dSCy Schubert 			/*
2052b15cb3dSCy Schubert 			 * work around problem mixing
2062b15cb3dSCy Schubert 			 * stdout & stderr
2072b15cb3dSCy Schubert 			 */
2082b15cb3dSCy Schubert 			fputs("", stdout);
2092b15cb3dSCy Schubert # endif	/* VMS */
2102b15cb3dSCy Schubert 
2112b15cb3dSCy Schubert 		fputs(lineedit_prompt, stderr);
2122b15cb3dSCy Schubert 		fflush(stderr);
2132b15cb3dSCy Schubert 	}
2142b15cb3dSCy Schubert 
2152b15cb3dSCy Schubert 	line = fgets(line_buf, sizeof(line_buf), stdin);
2162b15cb3dSCy Schubert 	if (NULL != line && *line) {
217*3311ff84SXin LI 		*pcount = (int)strlen(line); /* cannot overflow here */
2182b15cb3dSCy Schubert 		line = estrdup(line);
2192b15cb3dSCy Schubert 	} else
2202b15cb3dSCy Schubert 		line = NULL;
2212b15cb3dSCy Schubert 
2222b15cb3dSCy Schubert #endif	/* LE_NONE */
2232b15cb3dSCy Schubert 
2242b15cb3dSCy Schubert 
2252b15cb3dSCy Schubert 	if (!line)			/* EOF */
2262b15cb3dSCy Schubert 		fputs("\n", stderr);
2272b15cb3dSCy Schubert 
2282b15cb3dSCy Schubert 	return line;
2292b15cb3dSCy Schubert }
2302b15cb3dSCy Schubert 
2312b15cb3dSCy Schubert 
2322b15cb3dSCy Schubert #ifdef LE_EDITLINE
2332b15cb3dSCy Schubert /*
2342b15cb3dSCy Schubert  * ntp_prompt_callback - return prompt string to el_gets()
2352b15cb3dSCy Schubert  */
2362b15cb3dSCy Schubert char *
ntp_prompt_callback(EditLine * el)2372b15cb3dSCy Schubert ntp_prompt_callback(
2382b15cb3dSCy Schubert 	EditLine *el
2392b15cb3dSCy Schubert 	)
2402b15cb3dSCy Schubert {
2412b15cb3dSCy Schubert 	UNUSED_ARG(el);
2422b15cb3dSCy Schubert 
2432b15cb3dSCy Schubert 	return lineedit_prompt;
2442b15cb3dSCy Schubert }
2452b15cb3dSCy Schubert #endif /* LE_EDITLINE */
2462b15cb3dSCy Schubert 
247