xref: /netbsd-src/lib/libedit/eln.c (revision 53362837009c78cd7a28e87924538d76e241edef)
1*53362837Schristos /*	$NetBSD: eln.c,v 1.38 2024/05/17 02:59:08 christos Exp $	*/
234e53048Schristos 
334e53048Schristos /*-
434e53048Schristos  * Copyright (c) 2009 The NetBSD Foundation, Inc.
534e53048Schristos  * All rights reserved.
634e53048Schristos  *
734e53048Schristos  * Redistribution and use in source and binary forms, with or without
834e53048Schristos  * modification, are permitted provided that the following conditions
934e53048Schristos  * are met:
1034e53048Schristos  * 1. Redistributions of source code must retain the above copyright
1134e53048Schristos  *    notice, this list of conditions and the following disclaimer.
1234e53048Schristos  * 2. Redistributions in binary form must reproduce the above copyright
1334e53048Schristos  *    notice, this list of conditions and the following disclaimer in the
1434e53048Schristos  *    documentation and/or other materials provided with the distribution.
1534e53048Schristos  *
1634e53048Schristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1734e53048Schristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1834e53048Schristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1934e53048Schristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2034e53048Schristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2134e53048Schristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2234e53048Schristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2334e53048Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2434e53048Schristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2534e53048Schristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2634e53048Schristos  * POSSIBILITY OF SUCH DAMAGE.
2734e53048Schristos  */
2834e53048Schristos #include "config.h"
2934e53048Schristos #if !defined(lint) && !defined(SCCSID)
30*53362837Schristos __RCSID("$NetBSD: eln.c,v 1.38 2024/05/17 02:59:08 christos Exp $");
3134e53048Schristos #endif /* not lint && not SCCSID */
3234e53048Schristos 
332884af9fSchristos #include <errno.h>
3434e53048Schristos #include <stdarg.h>
3534e53048Schristos #include <stdio.h>
360b9ae3fdSchristos #include <stdlib.h>
3734e53048Schristos 
38aefc1e44Schristos #include "el.h"
39aefc1e44Schristos 
40469d44f8Schristos int
el_getc(EditLine * el,char * cp)4134e53048Schristos el_getc(EditLine *el, char *cp)
4234e53048Schristos {
4334e53048Schristos 	int num_read;
4434e53048Schristos 	wchar_t wc = 0;
4534e53048Schristos 
4634e53048Schristos 	num_read = el_wgetc(el, &wc);
472884af9fSchristos 	*cp = '\0';
482884af9fSchristos 	if (num_read <= 0)
4934e53048Schristos 		return num_read;
50fcf85103Schristos 	num_read = wctob(wc);
512884af9fSchristos 	if (num_read == EOF) {
522884af9fSchristos 		errno = ERANGE;
532884af9fSchristos 		return -1;
542884af9fSchristos 	} else {
552884af9fSchristos 		*cp = (char)num_read;
562884af9fSchristos 		return 1;
572884af9fSchristos 	}
5834e53048Schristos }
5934e53048Schristos 
6034e53048Schristos 
61469d44f8Schristos void
el_push(EditLine * el,const char * str)6234e53048Schristos el_push(EditLine *el, const char *str)
6334e53048Schristos {
6434e53048Schristos 	/* Using multibyte->wide string decoding works fine under single-byte
6534e53048Schristos 	 * character sets too, and Does The Right Thing. */
6634e53048Schristos 	el_wpush(el, ct_decode_string(str, &el->el_lgcyconv));
6734e53048Schristos }
6834e53048Schristos 
6934e53048Schristos 
70469d44f8Schristos const char *
el_gets(EditLine * el,int * nread)7134e53048Schristos el_gets(EditLine *el, int *nread)
7234e53048Schristos {
736fbbcd94Schristos 	const wchar_t *tmp;
746fbbcd94Schristos 
756fbbcd94Schristos 	tmp = el_wgets(el, nread);
76bdf16bcaSchristos 	if (tmp != NULL) {
77cc7f005fSchristos 	    int i;
78bdf16bcaSchristos 	    size_t nwread = 0;
79cc7f005fSchristos 
80cc7f005fSchristos 	    for (i = 0; i < *nread; i++)
81bdf16bcaSchristos 		nwread += ct_enc_width(tmp[i]);
82bdf16bcaSchristos 	    *nread = (int)nwread;
83bdf16bcaSchristos 	}
846fbbcd94Schristos 	return ct_encode_string(tmp, &el->el_lgcyconv);
8534e53048Schristos }
8634e53048Schristos 
8734e53048Schristos 
88469d44f8Schristos int
el_parse(EditLine * el,int argc,const char * argv[])8934e53048Schristos el_parse(EditLine *el, int argc, const char *argv[])
9034e53048Schristos {
9134e53048Schristos 	int ret;
9234e53048Schristos 	const wchar_t **wargv;
9334e53048Schristos 
94ecb8efd1Schristos 	wargv = (void *)ct_decode_argv(argc, argv, &el->el_lgcyconv);
9534e53048Schristos 	if (!wargv)
9634e53048Schristos 		return -1;
9734e53048Schristos 	ret = el_wparse(el, argc, wargv);
98fcf85103Schristos 	el_free(wargv);
9934e53048Schristos 
10034e53048Schristos 	return ret;
10134e53048Schristos }
10234e53048Schristos 
10334e53048Schristos 
104469d44f8Schristos int
el_set(EditLine * el,int op,...)10534e53048Schristos el_set(EditLine *el, int op, ...)
10634e53048Schristos {
10734e53048Schristos 	va_list ap;
10834e53048Schristos 	int ret;
10934e53048Schristos 
11034e53048Schristos 	if (!el)
11134e53048Schristos 		return -1;
11234e53048Schristos 	va_start(ap, op);
11334e53048Schristos 
11434e53048Schristos 	switch (op) {
11534e53048Schristos 	case EL_PROMPT:         /* el_pfunc_t */
11634e53048Schristos 	case EL_RPROMPT: {
11734e53048Schristos 		el_pfunc_t p = va_arg(ap, el_pfunc_t);
11834e53048Schristos 		ret = prompt_set(el, p, 0, op, 0);
11934e53048Schristos 		break;
12034e53048Schristos 	}
12134e53048Schristos 
1227741aae9Schristos 	case EL_RESIZE: {
1237741aae9Schristos 		el_zfunc_t p = va_arg(ap, el_zfunc_t);
1247741aae9Schristos 		void *arg = va_arg(ap, void *);
1257741aae9Schristos 		ret = ch_resizefun(el, p, arg);
1267741aae9Schristos 		break;
1277741aae9Schristos 	}
1287741aae9Schristos 
129e06822a7Schristos 	case EL_ALIAS_TEXT: {
130e06822a7Schristos 		el_afunc_t p = va_arg(ap, el_afunc_t);
131e06822a7Schristos 		void *arg = va_arg(ap, void *);
132e06822a7Schristos 		ret = ch_aliasfun(el, p, arg);
133e06822a7Schristos 		break;
134e06822a7Schristos 	}
135e06822a7Schristos 
1360680d721Schristos 	case EL_PROMPT_ESC:
1370680d721Schristos 	case EL_RPROMPT_ESC: {
1380680d721Schristos 		el_pfunc_t p = va_arg(ap, el_pfunc_t);
1390680d721Schristos 		int c = va_arg(ap, int);
1400680d721Schristos 
1410680d721Schristos 		ret = prompt_set(el, p, c, op, 0);
1420680d721Schristos 		break;
1430680d721Schristos 	}
1440680d721Schristos 
14534e53048Schristos 	case EL_TERMINAL:       /* const char * */
14634e53048Schristos 		ret = el_wset(el, op, va_arg(ap, char *));
14734e53048Schristos 		break;
14834e53048Schristos 
149654f9c04Schristos 	case EL_EDITOR:		/* const wchar_t * */
150654f9c04Schristos 		ret = el_wset(el, op, ct_decode_string(va_arg(ap, char *),
151654f9c04Schristos 		    &el->el_lgcyconv));
152654f9c04Schristos 		break;
153654f9c04Schristos 
15434e53048Schristos 	case EL_SIGNAL:         /* int */
15534e53048Schristos 	case EL_EDITMODE:
156da69b70bSchristos 	case EL_SAFEREAD:
15734e53048Schristos 	case EL_UNBUFFERED:
15834e53048Schristos 	case EL_PREP_TERM:
15934e53048Schristos 		ret = el_wset(el, op, va_arg(ap, int));
16034e53048Schristos 		break;
16134e53048Schristos 
16234e53048Schristos 	case EL_BIND:   /* const char * list -> const wchar_t * list */
16334e53048Schristos 	case EL_TELLTC:
16434e53048Schristos 	case EL_SETTC:
16534e53048Schristos 	case EL_ECHOTC:
16634e53048Schristos 	case EL_SETTY: {
16734e53048Schristos 		const char *argv[20];
16834e53048Schristos 		int i;
16934e53048Schristos 		const wchar_t **wargv;
170368fe5a9Schristos 		for (i = 1; i < (int)__arraycount(argv) - 1; ++i)
171368fe5a9Schristos 			if ((argv[i] = va_arg(ap, const char *)) == NULL)
17234e53048Schristos 			    break;
173368fe5a9Schristos 		argv[0] = argv[i] = NULL;
174ecb8efd1Schristos 		wargv = (void *)ct_decode_argv(i + 1, argv, &el->el_lgcyconv);
17534e53048Schristos 		if (!wargv) {
17634e53048Schristos 		    ret = -1;
17734e53048Schristos 		    goto out;
17834e53048Schristos 		}
17934e53048Schristos 		/*
18034e53048Schristos 		 * AFAIK we can't portably pass through our new wargv to
18134e53048Schristos 		 * el_wset(), so we have to reimplement the body of
18234e53048Schristos 		 * el_wset() for these ops.
18334e53048Schristos 		 */
18434e53048Schristos 		switch (op) {
18534e53048Schristos 		case EL_BIND:
1860aefc7f9Schristos 			wargv[0] = L"bind";
18734e53048Schristos 			ret = map_bind(el, i, wargv);
18834e53048Schristos 			break;
18934e53048Schristos 		case EL_TELLTC:
1900aefc7f9Schristos 			wargv[0] = L"telltc";
19198c7cbebSchristos 			ret = terminal_telltc(el, i, wargv);
19234e53048Schristos 			break;
19334e53048Schristos 		case EL_SETTC:
1940aefc7f9Schristos 			wargv[0] = L"settc";
19598c7cbebSchristos 			ret = terminal_settc(el, i, wargv);
19634e53048Schristos 			break;
19734e53048Schristos 		case EL_ECHOTC:
1980aefc7f9Schristos 			wargv[0] = L"echotc";
19998c7cbebSchristos 			ret = terminal_echotc(el, i, wargv);
20034e53048Schristos 			break;
20134e53048Schristos 		case EL_SETTY:
2020aefc7f9Schristos 			wargv[0] = L"setty";
20334e53048Schristos 			ret = tty_stty(el, i, wargv);
20434e53048Schristos 			break;
20534e53048Schristos 		default:
20634e53048Schristos 			ret = -1;
20734e53048Schristos 		}
208fcf85103Schristos 		el_free(wargv);
20934e53048Schristos 		break;
21034e53048Schristos 	}
21134e53048Schristos 
21234e53048Schristos 	/* XXX: do we need to change el_func_t too? */
21334e53048Schristos 	case EL_ADDFN: {          /* const char *, const char *, el_func_t */
21434e53048Schristos 		const char *args[2];
21534e53048Schristos 		el_func_t func;
21634e53048Schristos 		wchar_t **wargv;
21734e53048Schristos 
21834e53048Schristos 		args[0] = va_arg(ap, const char *);
21934e53048Schristos 		args[1] = va_arg(ap, const char *);
22034e53048Schristos 		func = va_arg(ap, el_func_t);
22134e53048Schristos 
22234e53048Schristos 		wargv = ct_decode_argv(2, args, &el->el_lgcyconv);
22334e53048Schristos 		if (!wargv) {
22434e53048Schristos 		    ret = -1;
22534e53048Schristos 		    goto out;
22634e53048Schristos 		}
227f8ee3c55Schristos 		/* XXX: The two strdup's leak */
2280aefc7f9Schristos 		ret = map_addfunc(el, wcsdup(wargv[0]), wcsdup(wargv[1]),
229139d3d5aSchristos 		    func);
230fcf85103Schristos 		el_free(wargv);
23134e53048Schristos 		break;
23234e53048Schristos 	}
23334e53048Schristos 	case EL_HIST: {           /* hist_fun_t, const char * */
23434e53048Schristos 		hist_fun_t fun = va_arg(ap, hist_fun_t);
235a13cd756Schristos 		void *ptr = va_arg(ap, void *);
2360b9ae3fdSchristos 		ret = hist_set(el, fun, ptr);
2370b9ae3fdSchristos 		el->el_flags |= NARROW_HISTORY;
23834e53048Schristos 		break;
23934e53048Schristos 	}
2400680d721Schristos 
24134e53048Schristos 	case EL_GETCFN:         /* el_rfunc_t */
24234e53048Schristos 		ret = el_wset(el, op, va_arg(ap, el_rfunc_t));
24334e53048Schristos 		break;
2440680d721Schristos 
24534e53048Schristos 	case EL_CLIENTDATA:     /* void * */
24634e53048Schristos 		ret = el_wset(el, op, va_arg(ap, void *));
24734e53048Schristos 		break;
2480680d721Schristos 
24934e53048Schristos 	case EL_SETFP: {          /* int, FILE * */
25034e53048Schristos 		int what = va_arg(ap, int);
25134e53048Schristos 		FILE *fp = va_arg(ap, FILE *);
25234e53048Schristos 		ret = el_wset(el, op, what, fp);
25334e53048Schristos 		break;
25434e53048Schristos 	}
2550680d721Schristos 
2560680d721Schristos 	case EL_REFRESH:
2570680d721Schristos 		re_clear_display(el);
2580680d721Schristos 		re_refresh(el);
2590680d721Schristos 		terminal__flush(el);
2600680d721Schristos 		ret = 0;
26134e53048Schristos 		break;
2620680d721Schristos 
26334e53048Schristos 	default:
26434e53048Schristos 		ret = -1;
26534e53048Schristos 		break;
26634e53048Schristos 	}
26734e53048Schristos 
26834e53048Schristos out:
26934e53048Schristos 	va_end(ap);
27034e53048Schristos 	return ret;
27134e53048Schristos }
27234e53048Schristos 
27334e53048Schristos 
274469d44f8Schristos int
el_get(EditLine * el,int op,...)27534e53048Schristos el_get(EditLine *el, int op, ...)
27634e53048Schristos {
27734e53048Schristos 	va_list ap;
27834e53048Schristos 	int ret;
27934e53048Schristos 
28034e53048Schristos 	if (!el)
28134e53048Schristos 		return -1;
28234e53048Schristos 
28334e53048Schristos 	va_start(ap, op);
28434e53048Schristos 
28534e53048Schristos 	switch (op) {
28634e53048Schristos 	case EL_PROMPT:         /* el_pfunc_t * */
28734e53048Schristos 	case EL_RPROMPT: {
28834e53048Schristos 		el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
2890b9ae3fdSchristos 		ret = prompt_get(el, p, 0, op);
29034e53048Schristos 		break;
29134e53048Schristos 	}
29234e53048Schristos 
29334e53048Schristos 	case EL_PROMPT_ESC: /* el_pfunc_t *, char **/
29434e53048Schristos 	case EL_RPROMPT_ESC: {
29534e53048Schristos 		el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
29634e53048Schristos 		char *c = va_arg(ap, char *);
297493d3410Smrg 		wchar_t wc = 0;
2980b9ae3fdSchristos 		ret = prompt_get(el, p, &wc, op);
2993d802cf5Schristos 		*c = (char)wc;
30034e53048Schristos 		break;
30134e53048Schristos 	}
30234e53048Schristos 
30334e53048Schristos 	case EL_EDITOR: {
30434e53048Schristos 		const char **p = va_arg(ap, const char **);
30534e53048Schristos 		const wchar_t *pw;
30634e53048Schristos 		ret = el_wget(el, op, &pw);
30734e53048Schristos 		*p = ct_encode_string(pw, &el->el_lgcyconv);
30834e53048Schristos 		if (!el->el_lgcyconv.csize)
30934e53048Schristos 			ret = -1;
31034e53048Schristos 		break;
31134e53048Schristos 	}
31234e53048Schristos 
31334e53048Schristos 	case EL_TERMINAL:       /* const char ** */
31434e53048Schristos 		ret = el_wget(el, op, va_arg(ap, const char **));
31534e53048Schristos 		break;
31634e53048Schristos 
31734e53048Schristos 	case EL_SIGNAL:         /* int * */
31834e53048Schristos 	case EL_EDITMODE:
319da69b70bSchristos 	case EL_SAFEREAD:
32034e53048Schristos 	case EL_UNBUFFERED:
32134e53048Schristos 	case EL_PREP_TERM:
32234e53048Schristos 		ret = el_wget(el, op, va_arg(ap, int *));
32334e53048Schristos 		break;
32434e53048Schristos 
32534e53048Schristos 	case EL_GETTC: {
326ef72f68dSchristos 		char *argv[3];
32734e53048Schristos 		static char gettc[] = "gettc";
32834e53048Schristos 		argv[0] = gettc;
329ef72f68dSchristos 		argv[1] = va_arg(ap, char *);
330ef72f68dSchristos 		argv[2] = va_arg(ap, void *);
331ef72f68dSchristos 		ret = terminal_gettc(el, 3, argv);
33234e53048Schristos 		break;
33334e53048Schristos 	}
33434e53048Schristos 
33534e53048Schristos 	case EL_GETCFN:         /* el_rfunc_t */
33634e53048Schristos 		ret = el_wget(el, op, va_arg(ap, el_rfunc_t *));
33734e53048Schristos 		break;
33834e53048Schristos 
33934e53048Schristos 	case EL_CLIENTDATA:     /* void ** */
34034e53048Schristos 		ret = el_wget(el, op, va_arg(ap, void **));
34134e53048Schristos 		break;
34234e53048Schristos 
34334e53048Schristos 	case EL_GETFP: {          /* int, FILE ** */
34434e53048Schristos 		int what = va_arg(ap, int);
34534e53048Schristos 		FILE **fpp = va_arg(ap, FILE **);
34634e53048Schristos 		ret = el_wget(el, op, what, fpp);
34734e53048Schristos 		break;
34834e53048Schristos 	}
34934e53048Schristos 
35034e53048Schristos 	default:
35134e53048Schristos 		ret = -1;
35234e53048Schristos 		break;
35334e53048Schristos 	}
35434e53048Schristos 
35534e53048Schristos 	va_end(ap);
35634e53048Schristos 	return ret;
35734e53048Schristos }
35834e53048Schristos 
35934e53048Schristos 
36034e53048Schristos const LineInfo *
el_line(EditLine * el)36134e53048Schristos el_line(EditLine *el)
36234e53048Schristos {
36334e53048Schristos 	const LineInfoW *winfo = el_wline(el);
36434e53048Schristos 	LineInfo *info = &el->el_lgcylinfo;
365939651faSchristos 	size_t offset;
3660594af80Schristos 	const wchar_t *p;
36734e53048Schristos 
368*53362837Schristos 	if (el->el_flags & FROM_ELLINE)
369*53362837Schristos 		return info;
370*53362837Schristos 
371*53362837Schristos 	el->el_flags |= FROM_ELLINE;
37234e53048Schristos 	info->buffer   = ct_encode_string(winfo->buffer, &el->el_lgcyconv);
373939651faSchristos 
374939651faSchristos 	offset = 0;
375939651faSchristos 	for (p = winfo->buffer; p < winfo->cursor; p++)
376939651faSchristos 		offset += ct_enc_width(*p);
377939651faSchristos 	info->cursor = info->buffer + offset;
378939651faSchristos 
379939651faSchristos 	offset = 0;
380939651faSchristos 	for (p = winfo->buffer; p < winfo->lastchar; p++)
381939651faSchristos 		offset += ct_enc_width(*p);
382939651faSchristos 	info->lastchar = info->buffer + offset;
383939651faSchristos 
384*53362837Schristos 	if (el->el_chared.c_resizefun)
385*53362837Schristos 		(*el->el_chared.c_resizefun)(el, el->el_chared.c_resizearg);
386*53362837Schristos 	el->el_flags &= ~FROM_ELLINE;
387*53362837Schristos 
38834e53048Schristos 	return info;
38934e53048Schristos }
39034e53048Schristos 
39134e53048Schristos 
39234e53048Schristos int
el_insertstr(EditLine * el,const char * str)39334e53048Schristos el_insertstr(EditLine *el, const char *str)
39434e53048Schristos {
39534e53048Schristos 	return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv));
39634e53048Schristos }
397b7e56637Schristos 
398b7e56637Schristos int
el_replacestr(EditLine * el,const char * str)399b7e56637Schristos el_replacestr(EditLine *el, const char *str)
400b7e56637Schristos {
401b7e56637Schristos 	return el_wreplacestr(el, ct_decode_string(str, &el->el_lgcyconv));
402b7e56637Schristos }
403