1258945Sroberto/* 2258945Sroberto * ntp_lineedit.c - generic interface to various line editing libs 3258945Sroberto */ 4258945Sroberto#ifdef HAVE_CONFIG_H 5258945Sroberto# include <config.h> 6258945Sroberto#endif 7258945Sroberto 8258945Sroberto#include <errno.h> 9258945Sroberto#include <string.h> 10258945Sroberto#include <stdlib.h> 11258945Sroberto#include <stdio.h> 12258945Sroberto 13258945Sroberto#if defined(HAVE_READLINE_HISTORY) && \ 14258945Sroberto (!defined(HAVE_READLINE_HISTORY_H) || \ 15258945Sroberto !defined(HAVE_READLINE_READLINE_H)) 16258945Sroberto# undef HAVE_READLINE_HISTORY 17258945Sroberto#endif 18258945Sroberto#if defined(HAVE_READLINE_HISTORY) 19258945Sroberto# include <readline/readline.h> 20258945Sroberto# include <readline/history.h> 21258945Sroberto# define LE_READLINE 22258945Sroberto#elif defined(HAVE_HISTEDIT_H) 23258945Sroberto# include <histedit.h> 24258945Sroberto# define LE_EDITLINE 25258945Sroberto#else 26258945Sroberto# define LE_NONE 27258945Sroberto#endif 28258945Sroberto 29258945Sroberto#include "ntp.h" 30258945Sroberto#include "ntp_stdlib.h" 31258945Sroberto#include "ntp_lineedit.h" 32293423Sdelphij#include "safecast.h" 33258945Sroberto 34258945Sroberto#define MAXEDITLINE 512 35258945Sroberto 36258945Sroberto/* 37258945Sroberto * external references 38258945Sroberto */ 39258945Sroberto 40289764Sglebiusextern char const * progname; 41258945Sroberto 42258945Sroberto/* 43258945Sroberto * globals, private prototypes 44258945Sroberto */ 45258945Sroberto 46258945Srobertostatic int ntp_readline_initted; 47258945Srobertostatic char * lineedit_prompt; 48258945Sroberto 49258945Sroberto 50258945Sroberto#ifdef LE_EDITLINE 51258945Sroberto# ifndef H_SETSIZE 52258945Sroberto# define H_SETSIZE H_EVENT 53258945Sroberto# endif 54258945Srobertostatic EditLine * ntp_el; 55258945Srobertostatic History * ntp_hist; 56258945Srobertostatic HistEvent hev; 57258945Sroberto 58258945Srobertochar * ntp_prompt_callback(EditLine *); 59258945Sroberto#endif /* LE_EDITLINE */ 60258945Sroberto 61258945Sroberto 62258945Sroberto/* 63258945Sroberto * ntp_readline_init - setup, set or reset prompt string 64258945Sroberto */ 65258945Srobertoint 66258945Srobertontp_readline_init( 67258945Sroberto const char * prompt 68258945Sroberto ) 69258945Sroberto{ 70258945Sroberto int success; 71258945Sroberto 72258945Sroberto success = 1; 73258945Sroberto 74258945Sroberto if (prompt) { 75258945Sroberto if (lineedit_prompt) 76258945Sroberto free(lineedit_prompt); 77258945Sroberto lineedit_prompt = estrdup(prompt); 78258945Sroberto } 79258945Sroberto 80258945Sroberto#ifdef LE_EDITLINE 81258945Sroberto if (NULL == ntp_el) { 82258945Sroberto 83258945Sroberto# if 4 == EL_INIT_ARGS 84258945Sroberto ntp_el = el_init(progname, stdin, stdout, stderr); 85258945Sroberto# else 86258945Sroberto ntp_el = el_init(progname, stdin, stdout); 87258945Sroberto# endif 88258945Sroberto if (ntp_el) { 89258945Sroberto 90258945Sroberto el_set(ntp_el, EL_PROMPT, ntp_prompt_callback); 91258945Sroberto el_set(ntp_el, EL_EDITOR, "emacs"); 92258945Sroberto 93258945Sroberto ntp_hist = history_init(); 94258945Sroberto 95258945Sroberto if (NULL == ntp_hist) { 96258945Sroberto 97280849Scy mfprintf(stderr, "history_init(): %m\n"); 98258945Sroberto fflush(stderr); 99258945Sroberto 100258945Sroberto el_end(ntp_el); 101258945Sroberto ntp_el = NULL; 102258945Sroberto 103258945Sroberto success = 0; 104258945Sroberto 105258945Sroberto } else { 106280849Scy ZERO(hev); 107258945Sroberto#ifdef H_SETSIZE 108258945Sroberto history(ntp_hist, &hev, H_SETSIZE, 128); 109258945Sroberto#endif 110258945Sroberto el_set(ntp_el, EL_HIST, history, 111258945Sroberto ntp_hist); 112258945Sroberto /* use any .editrc */ 113258945Sroberto el_source(ntp_el, NULL); 114258945Sroberto } 115258945Sroberto } else 116258945Sroberto success = 0; 117258945Sroberto } 118258945Sroberto#endif /* LE_EDITLINE */ 119258945Sroberto 120258945Sroberto ntp_readline_initted = success; 121258945Sroberto 122258945Sroberto return success; 123258945Sroberto} 124258945Sroberto 125258945Sroberto 126258945Sroberto/* 127258945Sroberto * ntp_readline_uninit - release resources 128258945Sroberto */ 129258945Srobertovoid 130258945Srobertontp_readline_uninit( 131258945Sroberto void 132258945Sroberto ) 133258945Sroberto{ 134258945Sroberto#ifdef LE_EDITLINE 135258945Sroberto if (ntp_el) { 136258945Sroberto el_end(ntp_el); 137258945Sroberto ntp_el = NULL; 138258945Sroberto 139258945Sroberto history_end(ntp_hist); 140258945Sroberto ntp_hist = NULL; 141258945Sroberto } 142258945Sroberto#endif /* LE_EDITLINE */ 143258945Sroberto 144258945Sroberto if (lineedit_prompt) { 145258945Sroberto free(lineedit_prompt); 146258945Sroberto lineedit_prompt = NULL; 147258945Sroberto } 148258945Sroberto 149258945Sroberto ntp_readline_initted = 0; 150258945Sroberto} 151258945Sroberto 152258945Sroberto 153258945Sroberto/* 154258945Sroberto * ntp_readline - read a line with the line editor available 155258945Sroberto * 156258945Sroberto * The string returned must be released with free() 157258945Sroberto */ 158258945Sroberto 159258945Srobertochar * 160258945Srobertontp_readline( 161258945Sroberto int * pcount 162258945Sroberto ) 163258945Sroberto{ 164258945Sroberto char * line; 165258945Sroberto#ifdef LE_NONE 166258945Sroberto char line_buf[MAXEDITLINE]; 167258945Sroberto#endif 168258945Sroberto#ifdef LE_EDITLINE 169258945Sroberto const char * cline; 170258945Sroberto#endif 171258945Sroberto 172258945Sroberto if (!ntp_readline_initted) 173258945Sroberto return NULL; 174258945Sroberto 175258945Sroberto *pcount = 0; 176258945Sroberto 177258945Sroberto#ifdef LE_READLINE 178258945Sroberto line = readline(lineedit_prompt ? lineedit_prompt : ""); 179258945Sroberto if (NULL != line) { 180258945Sroberto if (*line) { 181258945Sroberto add_history(line); 182258945Sroberto } 183280849Scy *pcount = strlen(line); 184258945Sroberto } 185258945Sroberto#endif /* LE_READLINE */ 186258945Sroberto 187258945Sroberto#ifdef LE_EDITLINE 188258945Sroberto cline = el_gets(ntp_el, pcount); 189258945Sroberto 190280849Scy if (NULL != cline) { 191258945Sroberto history(ntp_hist, &hev, H_ENTER, cline); 192258945Sroberto line = estrdup(cline); 193280849Scy } else if (*pcount == -1) { 194258945Sroberto line = NULL; 195280849Scy } else { 196280849Scy line = estrdup(""); 197280849Scy } 198258945Sroberto#endif /* LE_EDITLINE */ 199258945Sroberto 200258945Sroberto#ifdef LE_NONE 201258945Sroberto /* stone hammers */ 202258945Sroberto if (lineedit_prompt) { 203258945Sroberto# ifdef VMS 204258945Sroberto /* 205258945Sroberto * work around problem mixing 206258945Sroberto * stdout & stderr 207258945Sroberto */ 208258945Sroberto fputs("", stdout); 209258945Sroberto# endif /* VMS */ 210258945Sroberto 211258945Sroberto fputs(lineedit_prompt, stderr); 212258945Sroberto fflush(stderr); 213258945Sroberto } 214258945Sroberto 215258945Sroberto line = fgets(line_buf, sizeof(line_buf), stdin); 216258945Sroberto if (NULL != line && *line) { 217293423Sdelphij *pcount = (int)strlen(line); /* cannot overflow here */ 218258945Sroberto line = estrdup(line); 219258945Sroberto } else 220258945Sroberto line = NULL; 221258945Sroberto 222258945Sroberto#endif /* LE_NONE */ 223258945Sroberto 224258945Sroberto 225258945Sroberto if (!line) /* EOF */ 226258945Sroberto fputs("\n", stderr); 227258945Sroberto 228258945Sroberto return line; 229258945Sroberto} 230258945Sroberto 231258945Sroberto 232258945Sroberto#ifdef LE_EDITLINE 233258945Sroberto/* 234258945Sroberto * ntp_prompt_callback - return prompt string to el_gets() 235258945Sroberto */ 236258945Srobertochar * 237258945Srobertontp_prompt_callback( 238258945Sroberto EditLine *el 239258945Sroberto ) 240258945Sroberto{ 241258945Sroberto UNUSED_ARG(el); 242258945Sroberto 243258945Sroberto return lineedit_prompt; 244258945Sroberto} 245258945Sroberto#endif /* LE_EDITLINE */ 246258945Sroberto 247