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