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