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