xref: /freebsd/contrib/ntp/libntp/ntp_lineedit.c (revision 009e81b16465ea457c0e63fd49fe77f47cc27a5a)
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