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