1 /*
2 * ntp_lineedit.c - generic interface to various line editing libs
3 */
4 #ifdef HAVE_CONFIG_H
5 # include <config.h>
6 #endif
7
8 #include <errno.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12
13 #if defined(HAVE_READLINE_HISTORY) && \
14 (!defined(HAVE_READLINE_HISTORY_H) || \
15 !defined(HAVE_READLINE_READLINE_H))
16 # undef HAVE_READLINE_HISTORY
17 #endif
18 #if defined(HAVE_READLINE_HISTORY)
19 # include <readline/readline.h>
20 # include <readline/history.h>
21 # define LE_READLINE
22 #elif defined(HAVE_HISTEDIT_H)
23 # include <histedit.h>
24 # define LE_EDITLINE
25 #else
26 # define LE_NONE
27 #endif
28
29 #include "ntp.h"
30 #include "ntp_stdlib.h"
31 #include "ntp_lineedit.h"
32 #include "safecast.h"
33
34 #define MAXEDITLINE 512
35
36 /*
37 * external references
38 */
39
40 extern char const * progname;
41
42 /*
43 * globals, private prototypes
44 */
45
46 static int ntp_readline_initted;
47 static char * lineedit_prompt;
48
49
50 #ifdef LE_EDITLINE
51 # ifndef H_SETSIZE
52 # define H_SETSIZE H_EVENT
53 # endif
54 static EditLine * ntp_el;
55 static History * ntp_hist;
56 static HistEvent hev;
57
58 char * ntp_prompt_callback(EditLine *);
59 #endif /* LE_EDITLINE */
60
61
62 /*
63 * ntp_readline_init - setup, set or reset prompt string
64 */
65 int
ntp_readline_init(const char * prompt)66 ntp_readline_init(
67 const char * prompt
68 )
69 {
70 int success;
71
72 success = 1;
73
74 if (prompt) {
75 if (lineedit_prompt)
76 free(lineedit_prompt);
77 lineedit_prompt = estrdup(prompt);
78 }
79
80 #ifdef LE_EDITLINE
81 if (NULL == ntp_el) {
82
83 # if 4 == EL_INIT_ARGS
84 ntp_el = el_init(progname, stdin, stdout, stderr);
85 # else
86 ntp_el = el_init(progname, stdin, stdout);
87 # endif
88 if (ntp_el) {
89
90 el_set(ntp_el, EL_PROMPT, ntp_prompt_callback);
91 el_set(ntp_el, EL_EDITOR, "emacs");
92
93 ntp_hist = history_init();
94
95 if (NULL == ntp_hist) {
96
97 mfprintf(stderr, "history_init(): %m\n");
98 fflush(stderr);
99
100 el_end(ntp_el);
101 ntp_el = NULL;
102
103 success = 0;
104
105 } else {
106 ZERO(hev);
107 #ifdef H_SETSIZE
108 history(ntp_hist, &hev, H_SETSIZE, 128);
109 #endif
110 el_set(ntp_el, EL_HIST, history,
111 ntp_hist);
112 /* use any .editrc */
113 el_source(ntp_el, NULL);
114 }
115 } else
116 success = 0;
117 }
118 #endif /* LE_EDITLINE */
119
120 ntp_readline_initted = success;
121
122 return success;
123 }
124
125
126 /*
127 * ntp_readline_uninit - release resources
128 */
129 void
ntp_readline_uninit(void)130 ntp_readline_uninit(
131 void
132 )
133 {
134 #ifdef LE_EDITLINE
135 if (ntp_el) {
136 el_end(ntp_el);
137 ntp_el = NULL;
138
139 history_end(ntp_hist);
140 ntp_hist = NULL;
141 }
142 #endif /* LE_EDITLINE */
143
144 if (lineedit_prompt) {
145 free(lineedit_prompt);
146 lineedit_prompt = NULL;
147 }
148
149 ntp_readline_initted = 0;
150 }
151
152
153 /*
154 * ntp_readline - read a line with the line editor available
155 *
156 * The string returned must be released with free()
157 */
158
159 char *
ntp_readline(int * pcount)160 ntp_readline(
161 int * pcount
162 )
163 {
164 char * line;
165 #ifdef LE_NONE
166 char line_buf[MAXEDITLINE];
167 #endif
168 #ifdef LE_EDITLINE
169 const char * cline;
170 #endif
171
172 if (!ntp_readline_initted)
173 return NULL;
174
175 *pcount = 0;
176
177 #ifdef LE_READLINE
178 line = readline(lineedit_prompt ? lineedit_prompt : "");
179 if (NULL != line) {
180 if (*line) {
181 add_history(line);
182 }
183 *pcount = strlen(line);
184 }
185 #endif /* LE_READLINE */
186
187 #ifdef LE_EDITLINE
188 cline = el_gets(ntp_el, pcount);
189
190 if (NULL != cline) {
191 history(ntp_hist, &hev, H_ENTER, cline);
192 line = estrdup(cline);
193 } else if (*pcount == -1) {
194 line = NULL;
195 } else {
196 line = estrdup("");
197 }
198 #endif /* LE_EDITLINE */
199
200 #ifdef LE_NONE
201 /* stone hammers */
202 if (lineedit_prompt) {
203 # ifdef VMS
204 /*
205 * work around problem mixing
206 * stdout & stderr
207 */
208 fputs("", stdout);
209 # endif /* VMS */
210
211 fputs(lineedit_prompt, stderr);
212 fflush(stderr);
213 }
214
215 line = fgets(line_buf, sizeof(line_buf), stdin);
216 if (NULL != line && *line) {
217 *pcount = (int)strlen(line); /* cannot overflow here */
218 line = estrdup(line);
219 } else
220 line = NULL;
221
222 #endif /* LE_NONE */
223
224
225 if (!line) /* EOF */
226 fputs("\n", stderr);
227
228 return line;
229 }
230
231
232 #ifdef LE_EDITLINE
233 /*
234 * ntp_prompt_callback - return prompt string to el_gets()
235 */
236 char *
ntp_prompt_callback(EditLine * el)237 ntp_prompt_callback(
238 EditLine *el
239 )
240 {
241 UNUSED_ARG(el);
242
243 return lineedit_prompt;
244 }
245 #endif /* LE_EDITLINE */
246
247