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