Home | History | Annotate | Line # | Download | only in libntp
      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