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 40extern char const * progname; 41 42/* 43 * globals, private prototypes 44 */ 45 46static int ntp_readline_initted; 47static char * lineedit_prompt; 48 49 50#ifdef LE_EDITLINE 51# ifndef H_SETSIZE 52# define H_SETSIZE H_EVENT 53# endif 54static EditLine * ntp_el; 55static History * ntp_hist; 56static HistEvent hev; 57 58char * ntp_prompt_callback(EditLine *); 59#endif /* LE_EDITLINE */ 60 61 62/* 63 * ntp_readline_init - setup, set or reset prompt string 64 */ 65int 66ntp_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 */ 129void 130ntp_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 159char * 160ntp_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 */ 236char * 237ntp_prompt_callback( 238 EditLine *el 239 ) 240{ 241 UNUSED_ARG(el); 242 243 return lineedit_prompt; 244} 245#endif /* LE_EDITLINE */ 246 247