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