GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libedit/eln.c Lines: 61 149 40.9 %
Date: 2017-11-07 Branches: 34 143 23.8 %

Line Branch Exec Source
1
/*	$OpenBSD: eln.c,v 1.18 2016/04/11 21:17:29 schwarze 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
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
 * POSSIBILITY OF SUCH DAMAGE.
28
 */
29
#include "config.h"
30
31
#include <errno.h>
32
#include <stdarg.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
36
#include "el.h"
37
38
int
39
el_getc(EditLine *el, char *cp)
40
{
41
	int num_read;
42
	wchar_t wc = 0;
43
44
	num_read = el_wgetc(el, &wc);
45
	*cp = '\0';
46
	if (num_read <= 0)
47
		return num_read;
48
	num_read = wctob(wc);
49
	if (num_read == EOF) {
50
		errno = ERANGE;
51
		return -1;
52
	} else {
53
		*cp = num_read;
54
		return 1;
55
	}
56
}
57
58
59
void
60
el_push(EditLine *el, const char *str)
61
{
62
	/* Using multibyte->wide string decoding works fine under single-byte
63
	 * character sets too, and Does The Right Thing. */
64
	el_wpush(el, ct_decode_string(str, &el->el_lgcyconv));
65
}
66
67
68
const char *
69
el_gets(EditLine *el, int *nread)
70
{
71
	const wchar_t *tmp;
72
	wchar_t *rd, *wr;
73
74
	if ((tmp = el_wgets(el, nread)) == NULL)
75
		return NULL;
76
77
	/*
78
	 * Temporary until the libedit audit is complete:
79
	 * Filter out all non-ASCII characters.
80
	 */
81
	wr = (wchar_t *)tmp;
82
	for (rd = wr; *rd != L'\0'; rd++) {
83
		if (wr < rd)
84
			*wr = *rd;
85
		if (*rd < 128)
86
			wr++;
87
	}
88
	*wr = L'\0';
89
	*nread = wr - tmp;
90
91
	return ct_encode_string(tmp, &el->el_lgcyconv);
92
}
93
94
95
int
96
el_parse(EditLine *el, int argc, const char *argv[])
97
{
98
	int ret;
99
	const wchar_t **wargv;
100
101
	wargv = (const wchar_t **)
102
	    ct_decode_argv(argc, argv, &el->el_lgcyconv);
103
	if (!wargv)
104
		return -1;
105
	ret = el_wparse(el, argc, wargv);
106
	free(wargv);
107
108
	return ret;
109
}
110
111
112
int
113
el_set(EditLine *el, int op, ...)
114
{
115
108
	va_list ap;
116
	int ret;
117
118
54
	if (!el)
119
		return -1;
120
54
	va_start(ap, op);
121
122





54
	switch (op) {
123
	case EL_PROMPT:         /* el_pfunc_t */
124
	case EL_RPROMPT: {
125
18
		el_pfunc_t p = va_arg(ap, el_pfunc_t);
126
6
		ret = prompt_set(el, p, 0, op, 0);
127
		break;
128
	}
129
130
	case EL_RESIZE: {
131
18
		el_zfunc_t p = va_arg(ap, el_zfunc_t);
132
18
		void *arg = va_arg(ap, void *);
133
6
		ret = ch_resizefun(el, p, arg);
134
		break;
135
	}
136
137
	case EL_TERMINAL:       /* const char * */
138
		ret = el_wset(el, op, va_arg(ap, char *));
139
		break;
140
141
	case EL_EDITOR:		/* const wchar_t * */
142
24
		ret = el_wset(el, op, ct_decode_string(va_arg(ap, char *),
143
6
		    &el->el_lgcyconv));
144
6
		break;
145
146
	case EL_SIGNAL:         /* int */
147
	case EL_EDITMODE:
148
	case EL_UNBUFFERED:
149
	case EL_PREP_TERM:
150
18
		ret = el_wset(el, op, va_arg(ap, int));
151
6
		break;
152
153
	case EL_BIND:   /* const char * list -> const wchar_t * list */
154
	case EL_TELLTC:
155
	case EL_SETTC:
156
	case EL_ECHOTC:
157
	case EL_SETTY: {
158
12
		const char *argv[21];
159
		int i;
160
		const wchar_t **wargv;
161
72
		for (i = 1; i < (int)__arraycount(argv) - 1; ++i)
162

108
			if ((argv[i] = va_arg(ap, char *)) == NULL)
163
			    break;
164
12
		argv[0] = argv[i] = NULL;
165
		wargv = (const wchar_t **)
166
12
		    ct_decode_argv(i + 1, argv, &el->el_lgcyconv);
167
12
		if (!wargv) {
168
		    ret = -1;
169
		    goto out;
170
		}
171
		/*
172
		 * AFAIK we can't portably pass through our new wargv to
173
		 * el_wset(), so we have to reimplement the body of
174
		 * el_wset() for these ops.
175
		 */
176

12
		switch (op) {
177
		case EL_BIND:
178
12
			wargv[0] = L"bind";
179
12
			ret = map_bind(el, i, wargv);
180
12
			break;
181
		case EL_TELLTC:
182
			wargv[0] = L"telltc";
183
			ret = terminal_telltc(el, i, wargv);
184
			break;
185
		case EL_SETTC:
186
			wargv[0] = L"settc";
187
			ret = terminal_settc(el, i, wargv);
188
			break;
189
		case EL_ECHOTC:
190
			wargv[0] = L"echotc";
191
			ret = terminal_echotc(el, i, wargv);
192
			break;
193
		case EL_SETTY:
194
			wargv[0] = L"setty";
195
			ret = tty_stty(el, i, wargv);
196
			break;
197
		default:
198
			ret = -1;
199
		}
200
12
		free(wargv);
201
12
		break;
202
24
	}
203
204
	/* XXX: do we need to change el_func_t too? */
205
	case EL_ADDFN: {          /* const char *, const char *, el_func_t */
206
12
		const char *args[2];
207
		el_func_t func;
208
		wchar_t **wargv;
209
210
36
		args[0] = va_arg(ap, const char *);
211
36
		args[1] = va_arg(ap, const char *);
212
36
		func = va_arg(ap, el_func_t);
213
214
12
		wargv = ct_decode_argv(2, args, &el->el_lgcyconv);
215
12
		if (!wargv) {
216
		    ret = -1;
217
		    goto out;
218
		}
219
		/* XXX: The two strdup's leak */
220
12
		ret = map_addfunc(el, wcsdup(wargv[0]), wcsdup(wargv[1]),
221
		    func);
222
12
		free(wargv);
223
12
		break;
224
24
	}
225
	case EL_HIST: {           /* hist_fun_t, const char * */
226
18
		hist_fun_t fun = va_arg(ap, hist_fun_t);
227
18
		void *ptr = va_arg(ap, void *);
228
6
		ret = hist_set(el, fun, ptr);
229
6
		el->el_flags |= NARROW_HISTORY;
230
		break;
231
	}
232
	case EL_GETCFN:         /* el_rfunc_t */
233
		ret = el_wset(el, op, va_arg(ap, el_rfunc_t));
234
		break;
235
	case EL_CLIENTDATA:     /* void * */
236
		ret = el_wset(el, op, va_arg(ap, void *));
237
		break;
238
	case EL_SETFP: {          /* int, FILE * */
239
		int what = va_arg(ap, int);
240
		FILE *fp = va_arg(ap, FILE *);
241
		ret = el_wset(el, op, what, fp);
242
		break;
243
	}
244
	case EL_PROMPT_ESC: /* el_pfunc_t, char */
245
	case EL_RPROMPT_ESC: {
246
		el_pfunc_t p = va_arg(ap, el_pfunc_t);
247
		char c = va_arg(ap, int);
248
		ret = prompt_set(el, p, c, op, 0);
249
		break;
250
	}
251
	default:
252
		ret = -1;
253
		break;
254
	}
255
256
out:
257
54
	va_end(ap);
258
54
	return ret;
259
54
}
260
261
262
int
263
el_get(EditLine *el, int op, ...)
264
{
265
12
	va_list ap;
266
	int ret;
267
268
6
	if (!el)
269
		return -1;
270
271
6
	va_start(ap, op);
272
273



6
	switch (op) {
274
	case EL_PROMPT:         /* el_pfunc_t * */
275
	case EL_RPROMPT: {
276
		el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
277
		ret = prompt_get(el, p, 0, op);
278
		break;
279
	}
280
281
	case EL_PROMPT_ESC: /* el_pfunc_t *, char **/
282
	case EL_RPROMPT_ESC: {
283
		el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
284
		char *c = va_arg(ap, char *);
285
		wchar_t wc = 0;
286
		ret = prompt_get(el, p, &wc, op);
287
		*c = (unsigned char)wc;
288
		break;
289
	}
290
291
	case EL_EDITOR: {
292
		const char **p = va_arg(ap, const char **);
293
		const wchar_t *pw;
294
		ret = el_wget(el, op, &pw);
295
		*p = ct_encode_string(pw, &el->el_lgcyconv);
296
		if (!el->el_lgcyconv.csize)
297
			ret = -1;
298
		break;
299
	}
300
301
	case EL_TERMINAL:       /* const char ** */
302
18
		ret = el_wget(el, op, va_arg(ap, const char **));
303
6
		break;
304
305
	case EL_SIGNAL:         /* int * */
306
	case EL_EDITMODE:
307
	case EL_UNBUFFERED:
308
	case EL_PREP_TERM:
309
		ret = el_wget(el, op, va_arg(ap, int *));
310
		break;
311
312
	case EL_GETTC: {
313
		char *argv[20];
314
		static char gettc[] = "gettc";
315
		int i;
316
		for (i = 1; i < (int)__arraycount(argv); ++i)
317
			if ((argv[i] = va_arg(ap, char *)) == NULL)
318
				break;
319
		argv[0] = gettc;
320
		ret = terminal_gettc(el, i, argv);
321
		break;
322
	}
323
324
	case EL_GETCFN:         /* el_rfunc_t */
325
		ret = el_wget(el, op, va_arg(ap, el_rfunc_t *));
326
		break;
327
328
	case EL_CLIENTDATA:     /* void ** */
329
		ret = el_wget(el, op, va_arg(ap, void **));
330
		break;
331
332
	case EL_GETFP: {          /* int, FILE ** */
333
		int what = va_arg(ap, int);
334
		FILE **fpp = va_arg(ap, FILE **);
335
		ret = el_wget(el, op, what, fpp);
336
		break;
337
	}
338
339
	default:
340
		ret = -1;
341
		break;
342
	}
343
344
6
	va_end(ap);
345
6
	return ret;
346
6
}
347
348
349
const LineInfo *
350
el_line(EditLine *el)
351
{
352
24
	const LineInfoW *winfo = el_wline(el);
353
12
	LineInfo *info = &el->el_lgcylinfo;
354
	size_t offset;
355
	const wchar_t *p;
356
357
12
	info->buffer   = ct_encode_string(winfo->buffer, &el->el_lgcyconv);
358
359
	offset = 0;
360
24
	for (p = winfo->buffer; p < winfo->cursor; p++)
361
		offset += ct_enc_width(*p);
362
12
	info->cursor = info->buffer + offset;
363
364
	offset = 0;
365
24
	for (p = winfo->buffer; p < winfo->lastchar; p++)
366
		offset += ct_enc_width(*p);
367
12
	info->lastchar = info->buffer + offset;
368
369
12
	return info;
370
}
371
372
373
int
374
el_insertstr(EditLine *el, const char *str)
375
{
376
	return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv));
377
}