xref: /dragonfly/contrib/libedit/src/eln.c (revision 698e9e6cd5f042847de67460caaa3fde98cdfe99)
1 /*        $NetBSD: eln.c,v 1.37 2022/01/11 18:30:15 christos Exp $    */
2 
3 /*-
4  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 #include "config.h"
29 #if !defined(lint) && !defined(SCCSID)
30 __RCSID("$NetBSD: eln.c,v 1.37 2022/01/11 18:30:15 christos Exp $");
31 #endif /* not lint && not SCCSID */
32 
33 #include <errno.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 
38 #include "el.h"
39 
40 int
el_getc(EditLine * el,char * cp)41 el_getc(EditLine *el, char *cp)
42 {
43           int num_read;
44           wchar_t wc = 0;
45 
46           num_read = el_wgetc(el, &wc);
47           *cp = '\0';
48           if (num_read <= 0)
49                     return num_read;
50           num_read = wctob(wc);
51           if (num_read == EOF) {
52                     errno = ERANGE;
53                     return -1;
54           } else {
55                     *cp = (char)num_read;
56                     return 1;
57           }
58 }
59 
60 
61 void
el_push(EditLine * el,const char * str)62 el_push(EditLine *el, const char *str)
63 {
64           /* Using multibyte->wide string decoding works fine under single-byte
65            * character sets too, and Does The Right Thing. */
66           el_wpush(el, ct_decode_string(str, &el->el_lgcyconv));
67 }
68 
69 
70 const char *
el_gets(EditLine * el,int * nread)71 el_gets(EditLine *el, int *nread)
72 {
73           const wchar_t *tmp;
74 
75           tmp = el_wgets(el, nread);
76           if (tmp != NULL) {
77               int i;
78               size_t nwread = 0;
79 
80               for (i = 0; i < *nread; i++)
81                     nwread += ct_enc_width(tmp[i]);
82               *nread = (int)nwread;
83           }
84           return ct_encode_string(tmp, &el->el_lgcyconv);
85 }
86 
87 
88 int
el_parse(EditLine * el,int argc,const char * argv[])89 el_parse(EditLine *el, int argc, const char *argv[])
90 {
91           int ret;
92           const wchar_t **wargv;
93 
94           wargv = (void *)ct_decode_argv(argc, argv, &el->el_lgcyconv);
95           if (!wargv)
96                     return -1;
97           ret = el_wparse(el, argc, wargv);
98           el_free(wargv);
99 
100           return ret;
101 }
102 
103 
104 int
el_set(EditLine * el,int op,...)105 el_set(EditLine *el, int op, ...)
106 {
107           va_list ap;
108           int ret;
109 
110           if (!el)
111                     return -1;
112           va_start(ap, op);
113 
114           switch (op) {
115           case EL_PROMPT:         /* el_pfunc_t */
116           case EL_RPROMPT: {
117                     el_pfunc_t p = va_arg(ap, el_pfunc_t);
118                     ret = prompt_set(el, p, 0, op, 0);
119                     break;
120           }
121 
122           case EL_RESIZE: {
123                     el_zfunc_t p = va_arg(ap, el_zfunc_t);
124                     void *arg = va_arg(ap, void *);
125                     ret = ch_resizefun(el, p, arg);
126                     break;
127           }
128 
129           case EL_ALIAS_TEXT: {
130                     el_afunc_t p = va_arg(ap, el_afunc_t);
131                     void *arg = va_arg(ap, void *);
132                     ret = ch_aliasfun(el, p, arg);
133                     break;
134           }
135 
136           case EL_PROMPT_ESC:
137           case EL_RPROMPT_ESC: {
138                     el_pfunc_t p = va_arg(ap, el_pfunc_t);
139                     int c = va_arg(ap, int);
140 
141                     ret = prompt_set(el, p, c, op, 0);
142                     break;
143           }
144 
145           case EL_TERMINAL:       /* const char * */
146                     ret = el_wset(el, op, va_arg(ap, char *));
147                     break;
148 
149           case EL_EDITOR:               /* const wchar_t * */
150                     ret = el_wset(el, op, ct_decode_string(va_arg(ap, char *),
151                         &el->el_lgcyconv));
152                     break;
153 
154           case EL_SIGNAL:         /* int */
155           case EL_EDITMODE:
156           case EL_SAFEREAD:
157           case EL_UNBUFFERED:
158           case EL_PREP_TERM:
159                     ret = el_wset(el, op, va_arg(ap, int));
160                     break;
161 
162           case EL_BIND:   /* const char * list -> const wchar_t * list */
163           case EL_TELLTC:
164           case EL_SETTC:
165           case EL_ECHOTC:
166           case EL_SETTY: {
167                     const char *argv[20];
168                     int i;
169                     const wchar_t **wargv;
170                     for (i = 1; i < (int)__arraycount(argv) - 1; ++i)
171                               if ((argv[i] = va_arg(ap, const char *)) == NULL)
172                                   break;
173                     argv[0] = argv[i] = NULL;
174                     wargv = (void *)ct_decode_argv(i + 1, argv, &el->el_lgcyconv);
175                     if (!wargv) {
176                         ret = -1;
177                         goto out;
178                     }
179                     /*
180                      * AFAIK we can't portably pass through our new wargv to
181                      * el_wset(), so we have to reimplement the body of
182                      * el_wset() for these ops.
183                      */
184                     switch (op) {
185                     case EL_BIND:
186                               wargv[0] = L"bind";
187                               ret = map_bind(el, i, wargv);
188                               break;
189                     case EL_TELLTC:
190                               wargv[0] = L"telltc";
191                               ret = terminal_telltc(el, i, wargv);
192                               break;
193                     case EL_SETTC:
194                               wargv[0] = L"settc";
195                               ret = terminal_settc(el, i, wargv);
196                               break;
197                     case EL_ECHOTC:
198                               wargv[0] = L"echotc";
199                               ret = terminal_echotc(el, i, wargv);
200                               break;
201                     case EL_SETTY:
202                               wargv[0] = L"setty";
203                               ret = tty_stty(el, i, wargv);
204                               break;
205                     default:
206                               ret = -1;
207                     }
208                     el_free(wargv);
209                     break;
210           }
211 
212           /* XXX: do we need to change el_func_t too? */
213           case EL_ADDFN: {          /* const char *, const char *, el_func_t */
214                     const char *args[2];
215                     el_func_t func;
216                     wchar_t **wargv;
217 
218                     args[0] = va_arg(ap, const char *);
219                     args[1] = va_arg(ap, const char *);
220                     func = va_arg(ap, el_func_t);
221 
222                     wargv = ct_decode_argv(2, args, &el->el_lgcyconv);
223                     if (!wargv) {
224                         ret = -1;
225                         goto out;
226                     }
227                     /* XXX: The two strdup's leak */
228                     ret = map_addfunc(el, wcsdup(wargv[0]), wcsdup(wargv[1]),
229                         func);
230                     el_free(wargv);
231                     break;
232           }
233           case EL_HIST: {           /* hist_fun_t, const char * */
234                     hist_fun_t fun = va_arg(ap, hist_fun_t);
235                     void *ptr = va_arg(ap, void *);
236                     ret = hist_set(el, fun, ptr);
237                     el->el_flags |= NARROW_HISTORY;
238                     break;
239           }
240 
241           case EL_GETCFN:         /* el_rfunc_t */
242                     ret = el_wset(el, op, va_arg(ap, el_rfunc_t));
243                     break;
244 
245           case EL_CLIENTDATA:     /* void * */
246                     ret = el_wset(el, op, va_arg(ap, void *));
247                     break;
248 
249           case EL_SETFP: {          /* int, FILE * */
250                     int what = va_arg(ap, int);
251                     FILE *fp = va_arg(ap, FILE *);
252                     ret = el_wset(el, op, what, fp);
253                     break;
254           }
255 
256           case EL_REFRESH:
257                     re_clear_display(el);
258                     re_refresh(el);
259                     terminal__flush(el);
260                     ret = 0;
261                     break;
262 
263           default:
264                     ret = -1;
265                     break;
266           }
267 
268 out:
269           va_end(ap);
270           return ret;
271 }
272 
273 
274 int
el_get(EditLine * el,int op,...)275 el_get(EditLine *el, int op, ...)
276 {
277           va_list ap;
278           int ret;
279 
280           if (!el)
281                     return -1;
282 
283           va_start(ap, op);
284 
285           switch (op) {
286           case EL_PROMPT:         /* el_pfunc_t * */
287           case EL_RPROMPT: {
288                     el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
289                     ret = prompt_get(el, p, 0, op);
290                     break;
291           }
292 
293           case EL_PROMPT_ESC: /* el_pfunc_t *, char **/
294           case EL_RPROMPT_ESC: {
295                     el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
296                     char *c = va_arg(ap, char *);
297                     wchar_t wc = 0;
298                     ret = prompt_get(el, p, &wc, op);
299                     *c = (char)wc;
300                     break;
301           }
302 
303           case EL_EDITOR: {
304                     const char **p = va_arg(ap, const char **);
305                     const wchar_t *pw;
306                     ret = el_wget(el, op, &pw);
307                     *p = ct_encode_string(pw, &el->el_lgcyconv);
308                     if (!el->el_lgcyconv.csize)
309                               ret = -1;
310                     break;
311           }
312 
313           case EL_TERMINAL:       /* const char ** */
314                     ret = el_wget(el, op, va_arg(ap, const char **));
315                     break;
316 
317           case EL_SIGNAL:         /* int * */
318           case EL_EDITMODE:
319           case EL_SAFEREAD:
320           case EL_UNBUFFERED:
321           case EL_PREP_TERM:
322                     ret = el_wget(el, op, va_arg(ap, int *));
323                     break;
324 
325           case EL_GETTC: {
326                     char *argv[3];
327                     static char gettc[] = "gettc";
328                     argv[0] = gettc;
329                     argv[1] = va_arg(ap, char *);
330                     argv[2] = va_arg(ap, void *);
331                     ret = terminal_gettc(el, 3, argv);
332                     break;
333           }
334 
335           case EL_GETCFN:         /* el_rfunc_t */
336                     ret = el_wget(el, op, va_arg(ap, el_rfunc_t *));
337                     break;
338 
339           case EL_CLIENTDATA:     /* void ** */
340                     ret = el_wget(el, op, va_arg(ap, void **));
341                     break;
342 
343           case EL_GETFP: {          /* int, FILE ** */
344                     int what = va_arg(ap, int);
345                     FILE **fpp = va_arg(ap, FILE **);
346                     ret = el_wget(el, op, what, fpp);
347                     break;
348           }
349 
350           default:
351                     ret = -1;
352                     break;
353           }
354 
355           va_end(ap);
356           return ret;
357 }
358 
359 
360 const LineInfo *
el_line(EditLine * el)361 el_line(EditLine *el)
362 {
363           const LineInfoW *winfo = el_wline(el);
364           LineInfo *info = &el->el_lgcylinfo;
365           size_t offset;
366           const wchar_t *p;
367 
368           info->buffer   = ct_encode_string(winfo->buffer, &el->el_lgcyconv);
369 
370           offset = 0;
371           for (p = winfo->buffer; p < winfo->cursor; p++)
372                     offset += ct_enc_width(*p);
373           info->cursor = info->buffer + offset;
374 
375           offset = 0;
376           for (p = winfo->buffer; p < winfo->lastchar; p++)
377                     offset += ct_enc_width(*p);
378           info->lastchar = info->buffer + offset;
379 
380           return info;
381 }
382 
383 
384 int
el_insertstr(EditLine * el,const char * str)385 el_insertstr(EditLine *el, const char *str)
386 {
387           return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv));
388 }
389 
390 int
el_replacestr(EditLine * el,const char * str)391 el_replacestr(EditLine *el, const char *str)
392 {
393           return el_wreplacestr(el, ct_decode_string(str, &el->el_lgcyconv));
394 }
395