Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libedit/read.c
39475 views
1
/* $NetBSD: read.c,v 1.109 2025/01/03 00:40:08 rillig Exp $ */
2
3
/*-
4
* Copyright (c) 1992, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Christos Zoulas of Cornell University.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
#include "config.h"
36
#if !defined(lint) && !defined(SCCSID)
37
#if 0
38
static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93";
39
#else
40
__RCSID("$NetBSD: read.c,v 1.109 2025/01/03 00:40:08 rillig Exp $");
41
#endif
42
#endif /* not lint && not SCCSID */
43
44
/*
45
* read.c: Terminal read functions
46
*/
47
#include <ctype.h>
48
#include <errno.h>
49
#include <fcntl.h>
50
#include <limits.h>
51
#include <stdlib.h>
52
#include <string.h>
53
#include <unistd.h>
54
55
#include "el.h"
56
#include "fcns.h"
57
#include "read.h"
58
59
#define EL_MAXMACRO 10
60
61
struct macros {
62
wchar_t **macro;
63
int level;
64
int offset;
65
};
66
67
struct el_read_t {
68
struct macros macros;
69
el_rfunc_t read_char; /* Function to read a character. */
70
int read_errno;
71
};
72
73
static int read__fixio(int, int);
74
static int read_char(EditLine *, wchar_t *);
75
static int read_getcmd(EditLine *, el_action_t *, wchar_t *);
76
static void read_clearmacros(struct macros *);
77
static void read_pop(struct macros *);
78
static const wchar_t *noedit_wgets(EditLine *, int *);
79
80
/* read_init():
81
* Initialize the read stuff
82
*/
83
libedit_private int
84
read_init(EditLine *el)
85
{
86
struct macros *ma;
87
88
if ((el->el_read = el_malloc(sizeof(*el->el_read))) == NULL)
89
return -1;
90
91
ma = &el->el_read->macros;
92
if ((ma->macro = el_calloc(EL_MAXMACRO, sizeof(*ma->macro))) == NULL)
93
goto out;
94
ma->level = -1;
95
ma->offset = 0;
96
97
/* builtin read_char */
98
el->el_read->read_char = read_char;
99
return 0;
100
out:
101
read_end(el);
102
return -1;
103
}
104
105
/* el_read_end():
106
* Free the data structures used by the read stuff.
107
*/
108
libedit_private void
109
read_end(EditLine *el)
110
{
111
112
read_clearmacros(&el->el_read->macros);
113
el_free(el->el_read->macros.macro);
114
el->el_read->macros.macro = NULL;
115
el_free(el->el_read);
116
el->el_read = NULL;
117
}
118
119
/* el_read_setfn():
120
* Set the read char function to the one provided.
121
* If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
122
*/
123
libedit_private int
124
el_read_setfn(struct el_read_t *el_read, el_rfunc_t rc)
125
{
126
el_read->read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
127
return 0;
128
}
129
130
131
/* el_read_getfn():
132
* return the current read char function, or EL_BUILTIN_GETCFN
133
* if it is the default one
134
*/
135
libedit_private el_rfunc_t
136
el_read_getfn(struct el_read_t *el_read)
137
{
138
return el_read->read_char == read_char ?
139
EL_BUILTIN_GETCFN : el_read->read_char;
140
}
141
142
143
/* read__fixio():
144
* Try to recover from a read error
145
*/
146
/* ARGSUSED */
147
static int
148
read__fixio(int fd __attribute__((__unused__)), int e)
149
{
150
151
switch (e) {
152
case -1: /* Make sure that the code is reachable */
153
154
#ifdef EWOULDBLOCK
155
case EWOULDBLOCK:
156
#ifndef TRY_AGAIN
157
#define TRY_AGAIN
158
#endif
159
#endif /* EWOULDBLOCK */
160
161
#if defined(POSIX) && defined(EAGAIN)
162
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
163
case EAGAIN:
164
#ifndef TRY_AGAIN
165
#define TRY_AGAIN
166
#endif
167
#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
168
#endif /* POSIX && EAGAIN */
169
170
e = 0;
171
#ifdef TRY_AGAIN
172
#if defined(F_SETFL) && defined(O_NDELAY)
173
if ((e = fcntl(fd, F_GETFL, 0)) == -1)
174
return -1;
175
176
if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
177
return -1;
178
else
179
e = 1;
180
#endif /* F_SETFL && O_NDELAY */
181
182
#ifdef FIONBIO
183
{
184
int zero = 0;
185
186
if (ioctl(fd, FIONBIO, &zero) == -1)
187
return -1;
188
else
189
e = 1;
190
}
191
#endif /* FIONBIO */
192
193
#endif /* TRY_AGAIN */
194
return e ? 0 : -1;
195
196
case EINTR:
197
return 0;
198
199
default:
200
return -1;
201
}
202
}
203
204
205
/* el_push():
206
* Push a macro
207
*/
208
void
209
el_wpush(EditLine *el, const wchar_t *str)
210
{
211
struct macros *ma = &el->el_read->macros;
212
213
if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
214
ma->level++;
215
if ((ma->macro[ma->level] = wcsdup(str)) != NULL)
216
return;
217
ma->level--;
218
}
219
terminal_beep(el);
220
terminal__flush(el);
221
}
222
223
224
/* read_getcmd():
225
* Get next command from the input stream,
226
* return 0 on success or -1 on EOF or error.
227
* Character values > 255 are not looked up in the map, but inserted.
228
*/
229
static int
230
read_getcmd(EditLine *el, el_action_t *cmdnum, wchar_t *ch)
231
{
232
static const wchar_t meta = (wchar_t)0x80;
233
el_action_t cmd;
234
235
do {
236
if (el_wgetc(el, ch) != 1)
237
return -1;
238
239
#ifdef KANJI
240
if ((*ch & meta)) {
241
el->el_state.metanext = 0;
242
cmd = CcViMap[' '];
243
break;
244
} else
245
#endif /* KANJI */
246
247
if (el->el_state.metanext) {
248
el->el_state.metanext = 0;
249
*ch |= meta;
250
}
251
if (*ch >= N_KEYS)
252
cmd = ED_INSERT;
253
else
254
cmd = el->el_map.current[(unsigned char) *ch];
255
if (cmd == ED_SEQUENCE_LEAD_IN) {
256
keymacro_value_t val;
257
switch (keymacro_get(el, ch, &val)) {
258
case XK_CMD:
259
cmd = val.cmd;
260
break;
261
case XK_STR:
262
el_wpush(el, val.str);
263
break;
264
case XK_NOD:
265
return -1;
266
default:
267
EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
268
}
269
}
270
} while (cmd == ED_SEQUENCE_LEAD_IN);
271
*cmdnum = cmd;
272
return 0;
273
}
274
275
/* read_char():
276
* Read a character from the tty.
277
*/
278
static int
279
read_char(EditLine *el, wchar_t *cp)
280
{
281
ssize_t num_read;
282
int tried = (el->el_flags & FIXIO) == 0;
283
char cbuf[MB_LEN_MAX];
284
size_t cbp = 0;
285
int save_errno = errno;
286
287
again:
288
el->el_signal->sig_no = 0;
289
while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) {
290
int e = errno;
291
switch (el->el_signal->sig_no) {
292
case SIGCONT:
293
el_wset(el, EL_REFRESH);
294
/*FALLTHROUGH*/
295
case SIGWINCH:
296
sig_set(el);
297
goto again;
298
default:
299
break;
300
}
301
if (!tried && read__fixio(el->el_infd, e) == 0) {
302
errno = save_errno;
303
tried = 1;
304
} else {
305
errno = e;
306
*cp = L'\0';
307
return -1;
308
}
309
}
310
311
/* Test for EOF */
312
if (num_read == 0) {
313
*cp = L'\0';
314
return 0;
315
}
316
317
for (;;) {
318
mbstate_t mbs;
319
320
++cbp;
321
/* This only works because UTF8 is stateless. */
322
memset(&mbs, 0, sizeof(mbs));
323
switch (mbrtowc(cp, cbuf, cbp, &mbs)) {
324
case (size_t)-1:
325
if (cbp > 1) {
326
/*
327
* Invalid sequence, discard all bytes
328
* except the last one.
329
*/
330
cbuf[0] = cbuf[cbp - 1];
331
cbp = 0;
332
break;
333
} else {
334
/* Invalid byte, discard it. */
335
cbp = 0;
336
goto again;
337
}
338
case (size_t)-2:
339
if (cbp >= MB_LEN_MAX) {
340
errno = EILSEQ;
341
*cp = L'\0';
342
return -1;
343
}
344
/* Incomplete sequence, read another byte. */
345
goto again;
346
default:
347
/* Valid character, process it. */
348
return 1;
349
}
350
}
351
}
352
353
/* read_pop():
354
* Pop a macro from the stack
355
*/
356
static void
357
read_pop(struct macros *ma)
358
{
359
int i;
360
361
el_free(ma->macro[0]);
362
for (i = 0; i < ma->level; i++)
363
ma->macro[i] = ma->macro[i + 1];
364
ma->level--;
365
ma->offset = 0;
366
}
367
368
static void
369
read_clearmacros(struct macros *ma)
370
{
371
while (ma->level >= 0)
372
el_free(ma->macro[ma->level--]);
373
ma->offset = 0;
374
}
375
376
/* el_wgetc():
377
* Read a wide character
378
*/
379
int
380
el_wgetc(EditLine *el, wchar_t *cp)
381
{
382
struct macros *ma = &el->el_read->macros;
383
int num_read;
384
385
terminal__flush(el);
386
for (;;) {
387
if (ma->level < 0)
388
break;
389
390
if (ma->macro[0][ma->offset] == '\0') {
391
read_pop(ma);
392
continue;
393
}
394
395
*cp = ma->macro[0][ma->offset++];
396
397
if (ma->macro[0][ma->offset] == '\0') {
398
/* Needed for QuoteMode On */
399
read_pop(ma);
400
}
401
402
return 1;
403
}
404
405
if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
406
return 0;
407
408
num_read = (*el->el_read->read_char)(el, cp);
409
410
/*
411
* Remember the original reason of a read failure
412
* such that el_wgets() can restore it after doing
413
* various cleanup operation that might change errno.
414
*/
415
if (num_read < 0)
416
el->el_read->read_errno = errno;
417
418
return num_read;
419
}
420
421
libedit_private void
422
read_prepare(EditLine *el)
423
{
424
if (el->el_flags & HANDLE_SIGNALS)
425
sig_set(el);
426
if (el->el_flags & NO_TTY)
427
return;
428
if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
429
tty_rawmode(el);
430
431
/* This is relatively cheap, and things go terribly wrong if
432
we have the wrong size. */
433
el_resize(el);
434
re_clear_display(el); /* reset the display stuff */
435
ch_reset(el);
436
re_refresh(el); /* print the prompt */
437
438
if (el->el_flags & UNBUFFERED)
439
terminal__flush(el);
440
}
441
442
libedit_private void
443
read_finish(EditLine *el)
444
{
445
if ((el->el_flags & UNBUFFERED) == 0)
446
(void) tty_cookedmode(el);
447
if (el->el_flags & HANDLE_SIGNALS)
448
sig_clr(el);
449
}
450
451
static const wchar_t *
452
noedit_wgets(EditLine *el, int *nread)
453
{
454
el_line_t *lp = &el->el_line;
455
int num;
456
457
while ((num = (*el->el_read->read_char)(el, lp->lastchar)) == 1) {
458
if (lp->lastchar + 1 >= lp->limit &&
459
!ch_enlargebufs(el, (size_t)2))
460
break;
461
lp->lastchar++;
462
if (el->el_flags & UNBUFFERED ||
463
lp->lastchar[-1] == '\r' ||
464
lp->lastchar[-1] == '\n')
465
break;
466
}
467
if (num == -1 && errno == EINTR)
468
lp->lastchar = lp->buffer;
469
lp->cursor = lp->lastchar;
470
*lp->lastchar = '\0';
471
*nread = (int)(lp->lastchar - lp->buffer);
472
return *nread ? lp->buffer : NULL;
473
}
474
475
const wchar_t *
476
el_wgets(EditLine *el, int *nread)
477
{
478
int retval;
479
el_action_t cmdnum = 0;
480
int num; /* how many chars we have read at NL */
481
wchar_t ch;
482
int nrb;
483
484
if (nread == NULL)
485
nread = &nrb;
486
*nread = 0;
487
el->el_read->read_errno = 0;
488
489
if (el->el_flags & NO_TTY) {
490
el->el_line.lastchar = el->el_line.buffer;
491
return noedit_wgets(el, nread);
492
}
493
494
#ifdef FIONREAD
495
if (el->el_tty.t_mode == EX_IO && el->el_read->macros.level < 0) {
496
int chrs = 0;
497
498
(void) ioctl(el->el_infd, FIONREAD, &chrs);
499
if (chrs == 0) {
500
if (tty_rawmode(el) < 0) {
501
errno = 0;
502
*nread = 0;
503
return NULL;
504
}
505
}
506
}
507
#endif /* FIONREAD */
508
509
if ((el->el_flags & UNBUFFERED) == 0)
510
read_prepare(el);
511
512
if (el->el_flags & EDIT_DISABLED) {
513
if ((el->el_flags & UNBUFFERED) == 0)
514
el->el_line.lastchar = el->el_line.buffer;
515
terminal__flush(el);
516
return noedit_wgets(el, nread);
517
}
518
519
for (num = -1; num == -1;) { /* while still editing this line */
520
/* if EOF or error */
521
if (read_getcmd(el, &cmdnum, &ch) == -1)
522
break;
523
if ((size_t)cmdnum >= el->el_map.nfunc) /* BUG CHECK command */
524
continue; /* try again */
525
/* now do the real command */
526
/* vi redo needs these way down the levels... */
527
el->el_state.thiscmd = cmdnum;
528
el->el_state.thisch = ch;
529
if (el->el_map.type == MAP_VI &&
530
el->el_map.current == el->el_map.key &&
531
el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
532
if (cmdnum == VI_DELETE_PREV_CHAR &&
533
el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
534
&& iswprint(el->el_chared.c_redo.pos[-1]))
535
el->el_chared.c_redo.pos--;
536
else
537
*el->el_chared.c_redo.pos++ = ch;
538
}
539
retval = (*el->el_map.func[cmdnum]) (el, ch);
540
541
/* save the last command here */
542
el->el_state.lastcmd = cmdnum;
543
544
/* use any return value */
545
switch (retval) {
546
case CC_CURSOR:
547
re_refresh_cursor(el);
548
break;
549
550
case CC_REDISPLAY:
551
re_clear_lines(el);
552
re_clear_display(el);
553
/* FALLTHROUGH */
554
555
case CC_REFRESH:
556
re_refresh(el);
557
break;
558
559
case CC_REFRESH_BEEP:
560
re_refresh(el);
561
terminal_beep(el);
562
break;
563
564
case CC_NORM: /* normal char */
565
break;
566
567
case CC_ARGHACK: /* Suggested by Rich Salz */
568
/* <[email protected]> */
569
continue; /* keep going... */
570
571
case CC_EOF: /* end of file typed */
572
if ((el->el_flags & UNBUFFERED) == 0)
573
num = 0;
574
else if (num == -1) {
575
*el->el_line.lastchar++ = CONTROL('d');
576
el->el_line.cursor = el->el_line.lastchar;
577
num = 1;
578
}
579
break;
580
581
case CC_NEWLINE: /* normal end of line */
582
num = (int)(el->el_line.lastchar - el->el_line.buffer);
583
break;
584
585
case CC_FATAL: /* fatal error, reset to known state */
586
/* put (real) cursor in a known place */
587
re_clear_display(el); /* reset the display stuff */
588
ch_reset(el); /* reset the input pointers */
589
read_clearmacros(&el->el_read->macros);
590
re_refresh(el); /* print the prompt again */
591
break;
592
593
case CC_ERROR:
594
default: /* functions we don't know about */
595
terminal_beep(el);
596
terminal__flush(el);
597
break;
598
}
599
el->el_state.argument = 1;
600
el->el_state.doingarg = 0;
601
el->el_chared.c_vcmd.action = NOP;
602
if (el->el_flags & UNBUFFERED)
603
break;
604
}
605
606
terminal__flush(el); /* flush any buffered output */
607
/* make sure the tty is set up correctly */
608
if ((el->el_flags & UNBUFFERED) == 0) {
609
read_finish(el);
610
*nread = num != -1 ? num : 0;
611
} else
612
*nread = (int)(el->el_line.lastchar - el->el_line.buffer);
613
614
if (*nread == 0) {
615
if (num == -1) {
616
*nread = -1;
617
if (el->el_read->read_errno)
618
errno = el->el_read->read_errno;
619
}
620
return NULL;
621
} else
622
return el->el_line.buffer;
623
}
624
625