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