GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
} |
Generated by: GCOVR (Version 3.3) |