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