/ lib / libedit / src / eln.c
eln.c
  1  /*	$NetBSD: eln.c,v 1.9 2010/11/04 13:53:12 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.9 2010/11/04 13:53:12 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 = (unsigned 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  
 79  	el->el_flags |= IGNORE_EXTCHARS;
 80  	tmp = el_wgets(el, nread);
 81  	el->el_flags &= ~IGNORE_EXTCHARS;
 82  	return ct_encode_string(tmp, &el->el_lgcyconv);
 83  }
 84  
 85  
 86  public int
 87  el_parse(EditLine *el, int argc, const char *argv[])
 88  {
 89  	int ret;
 90  	const wchar_t **wargv;
 91  
 92  	wargv = (const wchar_t **)
 93  	    ct_decode_argv(argc, argv, &el->el_lgcyconv);
 94  	if (!wargv)
 95  		return -1;
 96  	ret = el_wparse(el, argc, wargv);
 97  	ct_free_argv(wargv);
 98  
 99  	return ret;
100  }
101  
102  
103  public int
104  el_set(EditLine *el, int op, ...)
105  {
106  	va_list ap;
107  	int ret;
108  
109  	if (!el)
110  		return -1;
111  	va_start(ap, op);
112  
113  	switch (op) {
114  	case EL_PROMPT:         /* el_pfunc_t */
115  	case EL_RPROMPT: {
116  		el_pfunc_t p = va_arg(ap, el_pfunc_t);
117  		ret = prompt_set(el, p, 0, op, 0);
118  		break;
119  	}
120  
121  	case EL_RESIZE: {
122  		el_zfunc_t p = va_arg(ap, el_zfunc_t);
123  		void *arg = va_arg(ap, void *);
124  		ret = ch_resizefun(el, p, arg);
125  		break;
126  	}
127  
128  	case EL_TERMINAL:       /* const char * */
129  		ret = el_wset(el, op, va_arg(ap, char *));
130  		break;
131  
132  	case EL_EDITOR:		/* const wchar_t * */
133  		ret = el_wset(el, op, ct_decode_string(va_arg(ap, char *),
134  		    &el->el_lgcyconv));
135  		break;
136  
137  	case EL_SIGNAL:         /* int */
138  	case EL_EDITMODE:
139  	case EL_UNBUFFERED:
140  	case EL_PREP_TERM:
141  		ret = el_wset(el, op, va_arg(ap, int));
142  		break;
143  
144  	case EL_BIND:   /* const char * list -> const wchar_t * list */
145  	case EL_TELLTC:
146  	case EL_SETTC:
147  	case EL_ECHOTC:
148  	case EL_SETTY: {
149  		const char *argv[20];
150  		int i;
151  		const wchar_t **wargv;
152  		for (i = 1; i < (int)__arraycount(argv); ++i)
153  			if ((argv[i] = va_arg(ap, char *)) == NULL)
154  			    break;
155  		argv[0] = NULL;
156  		wargv = (const wchar_t **)
157  		    ct_decode_argv(i, argv, &el->el_lgcyconv);
158  		if (!wargv) {
159  		    ret = -1;
160  		    goto out;
161  		}
162  		/*
163  		 * AFAIK we can't portably pass through our new wargv to
164  		 * el_wset(), so we have to reimplement the body of
165  		 * el_wset() for these ops.
166  		 */
167  		switch (op) {
168  		case EL_BIND:
169  			wargv[0] = STR("bind");
170  			ret = map_bind(el, i, wargv);
171  			break;
172  		case EL_TELLTC:
173  			wargv[0] = STR("telltc");
174  			ret = term_telltc(el, i, wargv);
175  			break;
176  		case EL_SETTC:
177  			wargv[0] = STR("settc");
178  			ret = term_settc(el, i, wargv);
179  			break;
180  		case EL_ECHOTC:
181  			wargv[0] = STR("echotc");
182  			ret = term_echotc(el, i, wargv);
183  			break;
184  		case EL_SETTY:
185  			wargv[0] = STR("setty");
186  			ret = tty_stty(el, i, wargv);
187  			break;
188  		default:
189  			ret = -1;
190  		}
191  		ct_free_argv(wargv);
192  		break;
193  	}
194  
195  	/* XXX: do we need to change el_func_t too? */
196  	case EL_ADDFN: {          /* const char *, const char *, el_func_t */
197  		const char *args[2];
198  		el_func_t func;
199  		wchar_t **wargv;
200  
201  		args[0] = va_arg(ap, const char *);
202  		args[1] = va_arg(ap, const char *);
203  		func = va_arg(ap, el_func_t);
204  
205  		wargv = ct_decode_argv(2, args, &el->el_lgcyconv);
206  		if (!wargv) {
207  		    ret = -1;
208  		    goto out;
209  		}
210  		// XXX: The two strdup's leak
211  		ret = map_addfunc(el, Strdup(wargv[0]), Strdup(wargv[1]),
212  		    func);
213  		ct_free_argv(wargv);
214  		break;
215  	}
216  	case EL_HIST: {           /* hist_fun_t, const char * */
217  		hist_fun_t fun = va_arg(ap, hist_fun_t);
218  		ptr_t ptr = va_arg(ap, ptr_t);
219  		ret = hist_set(el, fun, ptr);
220  		el->el_flags |= NARROW_HISTORY;
221  		break;
222  	}
223  	/* XXX: do we need to change el_rfunc_t? */
224  	case EL_GETCFN:         /* el_rfunc_t */
225  		ret = el_wset(el, op, va_arg(ap, el_rfunc_t));
226  		el->el_flags |= NARROW_READ;
227  		break;
228  	case EL_CLIENTDATA:     /* void * */
229  		ret = el_wset(el, op, va_arg(ap, void *));
230  		break;
231  	case EL_SETFP: {          /* int, FILE * */
232  		int what = va_arg(ap, int);
233  		FILE *fp = va_arg(ap, FILE *);
234  		ret = el_wset(el, op, what, fp);
235  		break;
236  	}
237  	case EL_PROMPT_ESC: /* el_pfunc_t, char */
238  	case EL_RPROMPT_ESC: {
239  		el_pfunc_t p = va_arg(ap, el_pfunc_t);
240  		char c = va_arg(ap, int);
241  		ret = prompt_set(el, p, c, op, 0);
242  		break;
243  	}
244  	default:
245  		ret = -1;
246  		break;
247  	}
248  
249  out:
250  	va_end(ap);
251  	return ret;
252  }
253  
254  
255  public int
256  el_get(EditLine *el, int op, ...)
257  {
258  	va_list ap;
259  	int ret;
260  
261  	if (!el)
262  		return -1;
263  
264  	va_start(ap, op);
265  
266  	switch (op) {
267  	case EL_PROMPT:         /* el_pfunc_t * */
268  	case EL_RPROMPT: {
269  		el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
270  		ret = prompt_get(el, p, 0, op);
271  		break;
272  	}
273  
274  	case EL_PROMPT_ESC: /* el_pfunc_t *, char **/
275  	case EL_RPROMPT_ESC: {
276  		el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
277  		char *c = va_arg(ap, char *);
278  		wchar_t wc;
279  		ret = prompt_get(el, p, &wc, op);
280  		*c = (unsigned char)wc;
281  		break;
282  	}
283  
284  	case EL_EDITOR: {
285  		const char **p = va_arg(ap, const char **);
286  		const wchar_t *pw;
287  		ret = el_wget(el, op, &pw);
288  		*p = ct_encode_string(pw, &el->el_lgcyconv);
289  		if (!el->el_lgcyconv.csize)
290  			ret = -1;
291  		break;
292  	}
293  
294  	case EL_TERMINAL:       /* const char ** */
295  		ret = el_wget(el, op, va_arg(ap, const char **));
296  		break;
297  
298  	case EL_SIGNAL:         /* int * */
299  	case EL_EDITMODE:
300  	case EL_UNBUFFERED:
301  	case EL_PREP_TERM:
302  		ret = el_wget(el, op, va_arg(ap, int *));
303  		break;
304  
305  	case EL_GETTC: {
306  		char *argv[20];
307  		static char gettc[] = "gettc";
308  		int i;
309  		for (i = 1; i < (int)__arraycount(argv); ++i)
310  			if ((argv[i] = va_arg(ap, char *)) == NULL)
311  				break;
312  		argv[0] = gettc;
313  		ret = term_gettc(el, i, argv);
314  		break;
315  	}
316  
317  	/* XXX: do we need to change el_rfunc_t? */
318  	case EL_GETCFN:         /* el_rfunc_t */
319  		ret = el_wget(el, op, va_arg(ap, el_rfunc_t *));
320  		break;
321  
322  	case EL_CLIENTDATA:     /* void ** */
323  		ret = el_wget(el, op, va_arg(ap, void **));
324  		break;
325  
326  	case EL_GETFP: {          /* int, FILE ** */
327  		int what = va_arg(ap, int);
328  		FILE **fpp = va_arg(ap, FILE **);
329  		ret = el_wget(el, op, what, fpp);
330  		break;
331  	}
332  
333  	default:
334  		ret = -1;
335  		break;
336  	}
337  
338  	va_end(ap);
339  	return ret;
340  }
341  
342  
343  const LineInfo *
344  el_line(EditLine *el)
345  {
346  	const LineInfoW *winfo = el_wline(el);
347  	LineInfo *info = &el->el_lgcylinfo;
348  	size_t offset;
349  	const Char *p;
350  
351  	info->buffer   = ct_encode_string(winfo->buffer, &el->el_lgcyconv);
352  
353  	offset = 0;
354  	for (p = winfo->buffer; p < winfo->cursor; p++)
355  		offset += ct_enc_width(*p);
356  	info->cursor = info->buffer + offset;
357  
358  	offset = 0;
359  	for (p = winfo->buffer; p < winfo->lastchar; p++)
360  		offset += ct_enc_width(*p);
361  	info->lastchar = info->buffer + offset;
362  
363  	return info;
364  }
365  
366  
367  int
368  el_insertstr(EditLine *el, const char *str)
369  {
370  	return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv));
371  }