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