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 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 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 * 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 * 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