1 /* $NetBSD: read.c,v 1.71 2014/07/06 18:15:34 christos 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.71 2014/07/06 18:15:34 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 /*
47 * read.c: Clean this junk up! This is horrible code.
48 * Terminal read functions
49 */
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include <stdlib.h>
54 #include <limits.h>
55 #include "el.h"
56
57 #define OKCMD -1 /* must be -1! */
58
59 private int read__fixio(int, int);
60 private int read_preread(EditLine *);
61 private int read_char(EditLine *, Char *);
62 private int read_getcmd(EditLine *, el_action_t *, Char *);
63 private void read_pop(c_macro_t *);
64
65 /* read_init():
66 * Initialize the read stuff
67 */
68 protected int
read_init(EditLine * el)69 read_init(EditLine *el)
70 {
71 /* builtin read_char */
72 el->el_read.read_char = read_char;
73 return 0;
74 }
75
76
77 /* el_read_setfn():
78 * Set the read char function to the one provided.
79 * If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
80 */
81 protected int
el_read_setfn(EditLine * el,el_rfunc_t rc)82 el_read_setfn(EditLine *el, el_rfunc_t rc)
83 {
84 el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
85 return 0;
86 }
87
88
89 /* el_read_getfn():
90 * return the current read char function, or EL_BUILTIN_GETCFN
91 * if it is the default one
92 */
93 protected el_rfunc_t
el_read_getfn(EditLine * el)94 el_read_getfn(EditLine *el)
95 {
96 return el->el_read.read_char == read_char ?
97 EL_BUILTIN_GETCFN : el->el_read.read_char;
98 }
99
100
101 #ifndef MIN
102 #define MIN(A,B) ((A) < (B) ? (A) : (B))
103 #endif
104
105 #ifdef DEBUG_EDIT
106 private void
read_debug(EditLine * el)107 read_debug(EditLine *el)
108 {
109
110 if (el->el_line.cursor > el->el_line.lastchar)
111 (void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
112 if (el->el_line.cursor < el->el_line.buffer)
113 (void) fprintf(el->el_errfile, "cursor < buffer\r\n");
114 if (el->el_line.cursor > el->el_line.limit)
115 (void) fprintf(el->el_errfile, "cursor > limit\r\n");
116 if (el->el_line.lastchar > el->el_line.limit)
117 (void) fprintf(el->el_errfile, "lastchar > limit\r\n");
118 if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
119 (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
120 }
121 #endif /* DEBUG_EDIT */
122
123
124 /* read__fixio():
125 * Try to recover from a read error
126 */
127 /* ARGSUSED */
128 private int
read__fixio(int fd,int e)129 read__fixio(int fd __attribute__((__unused__)), int e)
130 {
131
132 switch (e) {
133 case -1: /* Make sure that the code is reachable */
134
135 #ifdef EWOULDBLOCK
136 case EWOULDBLOCK:
137 #ifndef TRY_AGAIN
138 #define TRY_AGAIN
139 #endif
140 #endif /* EWOULDBLOCK */
141
142 #if defined(POSIX) && defined(EAGAIN)
143 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
144 case EAGAIN:
145 #ifndef TRY_AGAIN
146 #define TRY_AGAIN
147 #endif
148 #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
149 #endif /* POSIX && EAGAIN */
150
151 e = 0;
152 #ifdef TRY_AGAIN
153 #if defined(F_SETFL) && defined(O_NDELAY)
154 if ((e = fcntl(fd, F_GETFL, 0)) == -1)
155 return -1;
156
157 if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
158 return -1;
159 else
160 e = 1;
161 #endif /* F_SETFL && O_NDELAY */
162
163 #ifdef FIONBIO
164 {
165 int zero = 0;
166
167 if (ioctl(fd, FIONBIO, &zero) == -1)
168 return -1;
169 else
170 e = 1;
171 }
172 #endif /* FIONBIO */
173
174 #endif /* TRY_AGAIN */
175 return e ? 0 : -1;
176
177 case EINTR:
178 return 0;
179
180 default:
181 return -1;
182 }
183 }
184
185
186 /* read_preread():
187 * Try to read the stuff in the input queue;
188 */
189 private int
read_preread(EditLine * el)190 read_preread(EditLine *el)
191 {
192 int chrs = 0;
193
194 if (el->el_tty.t_mode == ED_IO)
195 return 0;
196
197 #ifndef WIDECHAR
198 /* FIONREAD attempts to buffer up multiple bytes, and to make that work
199 * properly with partial wide/UTF-8 characters would need some careful work. */
200 #ifdef FIONREAD
201 (void) ioctl(el->el_infd, FIONREAD, &chrs);
202 if (chrs > 0) {
203 char buf[EL_BUFSIZ];
204
205 chrs = read(el->el_infd, buf,
206 (size_t) MIN(chrs, EL_BUFSIZ - 1));
207 if (chrs > 0) {
208 buf[chrs] = '\0';
209 el_push(el, buf);
210 }
211 }
212 #endif /* FIONREAD */
213 #endif
214 return chrs > 0;
215 }
216
217
218 /* el_push():
219 * Push a macro
220 */
221 public void
FUN(el,push)222 FUN(el,push)(EditLine *el, const Char *str)
223 {
224 c_macro_t *ma = &el->el_chared.c_macro;
225
226 if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
227 ma->level++;
228 if ((ma->macro[ma->level] = Strdup(str)) != NULL)
229 return;
230 ma->level--;
231 }
232 terminal_beep(el);
233 terminal__flush(el);
234 }
235
236
237 /* read_getcmd():
238 * Get next command from the input stream, return OKCMD on success.
239 * Character values > 255 are not looked up in the map, but inserted.
240 */
241 private int
read_getcmd(EditLine * el,el_action_t * cmdnum,Char * ch)242 read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch)
243 {
244 el_action_t cmd;
245 int num;
246
247 el->el_errno = 0;
248 do {
249 if ((num = FUN(el,getc)(el, ch)) != 1) {/* if EOF or error */
250 el->el_errno = num == 0 ? 0 : errno;
251 return 0; /* not OKCMD */
252 }
253
254 #ifdef KANJI
255 if ((*ch & 0200)) {
256 el->el_state.metanext = 0;
257 cmd = CcViMap[' '];
258 break;
259 } else
260 #endif /* KANJI */
261
262 if (el->el_state.metanext) {
263 el->el_state.metanext = 0;
264 *ch |= 0200;
265 }
266 #ifdef WIDECHAR
267 if (*ch >= N_KEYS)
268 cmd = ED_INSERT;
269 else
270 #endif
271 cmd = el->el_map.current[(unsigned char) *ch];
272 if (cmd == ED_SEQUENCE_LEAD_IN) {
273 keymacro_value_t val;
274 switch (keymacro_get(el, ch, &val)) {
275 case XK_CMD:
276 cmd = val.cmd;
277 break;
278 case XK_STR:
279 FUN(el,push)(el, val.str);
280 break;
281 #ifdef notyet
282 case XK_EXE:
283 /* XXX: In the future to run a user function */
284 RunCommand(val.str);
285 break;
286 #endif
287 default:
288 EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
289 break;
290 }
291 }
292 if (el->el_map.alt == NULL)
293 el->el_map.current = el->el_map.key;
294 } while (cmd == ED_SEQUENCE_LEAD_IN);
295 *cmdnum = cmd;
296 return OKCMD;
297 }
298
299 #ifdef WIDECHAR
300 /* utf8_islead():
301 * Test whether a byte is a leading byte of a UTF-8 sequence.
302 */
303 private int
utf8_islead(int c)304 utf8_islead(int c)
305 {
306 return c < 0x80 || /* single byte char */
307 (c >= 0xc2 && c <= 0xf4); /* start of multibyte sequence */
308 }
309 #endif
310
311 /* read_char():
312 * Read a character from the tty.
313 */
314 private int
read_char(EditLine * el,Char * cp)315 read_char(EditLine *el, Char *cp)
316 {
317 ssize_t num_read;
318 int tried = 0;
319 char cbuf[MB_LEN_MAX];
320 size_t cbp = 0;
321 int bytes = 0;
322
323 again:
324 el->el_signal->sig_no = 0;
325 while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) {
326 int e = errno;
327 switch (el->el_signal->sig_no) {
328 case SIGCONT:
329 FUN(el,set)(el, EL_REFRESH);
330 /*FALLTHROUGH*/
331 case SIGWINCH:
332 sig_set(el);
333 goto again;
334 default:
335 break;
336 }
337 if (!tried && read__fixio(el->el_infd, e) == 0)
338 tried = 1;
339 else {
340 errno = e;
341 *cp = '\0';
342 return -1;
343 }
344 }
345
346 /* Test for EOF */
347 if (num_read == 0) {
348 errno = 0;
349 *cp = '\0';
350 return 0;
351 }
352
353 #ifdef WIDECHAR
354 if (el->el_flags & CHARSET_IS_UTF8) {
355 if (!utf8_islead((unsigned char)cbuf[0]))
356 goto again; /* discard the byte we read and try again */
357 ++cbp;
358 if ((bytes = ct_mbtowc(cp, cbuf, cbp)) == -1) {
359 ct_mbtowc_reset;
360 if (cbp >= MB_LEN_MAX) { /* "shouldn't happen" */
361 errno = EILSEQ;
362 *cp = '\0';
363 return -1;
364 }
365 goto again;
366 }
367 } else if (isascii((unsigned char)cbuf[0]) ||
368 /* we don't support other multibyte charsets */
369 ++cbp != 1 ||
370 /* Try non-ASCII characters in a 8-bit character set */
371 (bytes = ct_mbtowc(cp, cbuf, cbp)) != 1)
372 #endif
373 *cp = (unsigned char)cbuf[0];
374
375 if ((el->el_flags & IGNORE_EXTCHARS) && bytes > 1) {
376 cbp = 0; /* skip this character */
377 goto again;
378 }
379
380 return (int)num_read;
381 }
382
383 /* read_pop():
384 * Pop a macro from the stack
385 */
386 private void
read_pop(c_macro_t * ma)387 read_pop(c_macro_t *ma)
388 {
389 int i;
390
391 el_free(ma->macro[0]);
392 for (i = 0; i < ma->level; i++)
393 ma->macro[i] = ma->macro[i + 1];
394 ma->level--;
395 ma->offset = 0;
396 }
397
398 /* el_getc():
399 * Read a character
400 */
401 public int
FUN(el,getc)402 FUN(el,getc)(EditLine *el, Char *cp)
403 {
404 int num_read;
405 c_macro_t *ma = &el->el_chared.c_macro;
406
407 terminal__flush(el);
408 for (;;) {
409 if (ma->level < 0) {
410 if (!read_preread(el))
411 break;
412 }
413
414 if (ma->level < 0)
415 break;
416
417 if (ma->macro[0][ma->offset] == '\0') {
418 read_pop(ma);
419 continue;
420 }
421
422 *cp = ma->macro[0][ma->offset++];
423
424 if (ma->macro[0][ma->offset] == '\0') {
425 /* Needed for QuoteMode On */
426 read_pop(ma);
427 }
428
429 return 1;
430 }
431
432 #ifdef DEBUG_READ
433 (void) fprintf(el->el_errfile, "Turning raw mode on\n");
434 #endif /* DEBUG_READ */
435 if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
436 return 0;
437
438 #ifdef DEBUG_READ
439 (void) fprintf(el->el_errfile, "Reading a character\n");
440 #endif /* DEBUG_READ */
441 num_read = (*el->el_read.read_char)(el, cp);
442 if (num_read < 0)
443 el->el_errno = errno;
444 #ifdef WIDECHAR
445 if (el->el_flags & NARROW_READ)
446 *cp = *(char *)(void *)cp;
447 #endif
448 #ifdef DEBUG_READ
449 (void) fprintf(el->el_errfile, "Got it %c\n", *cp);
450 #endif /* DEBUG_READ */
451 return num_read;
452 }
453
454 protected void
read_prepare(EditLine * el)455 read_prepare(EditLine *el)
456 {
457 if (el->el_flags & HANDLE_SIGNALS)
458 sig_set(el);
459 if (el->el_flags & NO_TTY)
460 return;
461 if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
462 tty_rawmode(el);
463
464 /* This is relatively cheap, and things go terribly wrong if
465 we have the wrong size. */
466 el_resize(el);
467 re_clear_display(el); /* reset the display stuff */
468 ch_reset(el, 0);
469 re_refresh(el); /* print the prompt */
470
471 if (el->el_flags & UNBUFFERED)
472 terminal__flush(el);
473 }
474
475 protected void
read_finish(EditLine * el)476 read_finish(EditLine *el)
477 {
478 if ((el->el_flags & UNBUFFERED) == 0)
479 (void) tty_cookedmode(el);
480 if (el->el_flags & HANDLE_SIGNALS)
481 sig_clr(el);
482 }
483
484 public const Char *
FUN(el,gets)485 FUN(el,gets)(EditLine *el, int *nread)
486 {
487 int retval;
488 el_action_t cmdnum = 0;
489 int num; /* how many chars we have read at NL */
490 Char ch, *cp;
491 int crlf = 0;
492 int nrb;
493 #ifdef FIONREAD
494 c_macro_t *ma = &el->el_chared.c_macro;
495 #endif /* FIONREAD */
496
497 if (nread == NULL)
498 nread = &nrb;
499 *nread = 0;
500
501 if (el->el_flags & NO_TTY) {
502 size_t idx;
503
504 cp = el->el_line.buffer;
505 while ((num = (*el->el_read.read_char)(el, cp)) == 1) {
506 /* make sure there is space for next character */
507 if (cp + 1 >= el->el_line.limit) {
508 idx = (size_t)(cp - el->el_line.buffer);
509 if (!ch_enlargebufs(el, (size_t)2))
510 break;
511 cp = &el->el_line.buffer[idx];
512 }
513 cp++;
514 if (el->el_flags & UNBUFFERED)
515 break;
516 if (cp[-1] == '\r' || cp[-1] == '\n')
517 break;
518 }
519 if (num == -1) {
520 if (errno == EINTR)
521 cp = el->el_line.buffer;
522 el->el_errno = errno;
523 }
524
525 goto noedit;
526 }
527
528
529 #ifdef FIONREAD
530 if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
531 long chrs = 0;
532
533 (void) ioctl(el->el_infd, FIONREAD, &chrs);
534 if (chrs == 0) {
535 if (tty_rawmode(el) < 0) {
536 errno = 0;
537 *nread = 0;
538 return NULL;
539 }
540 }
541 }
542 #endif /* FIONREAD */
543
544 if ((el->el_flags & UNBUFFERED) == 0)
545 read_prepare(el);
546
547 if (el->el_flags & EDIT_DISABLED) {
548 size_t idx;
549
550 if ((el->el_flags & UNBUFFERED) == 0)
551 cp = el->el_line.buffer;
552 else
553 cp = el->el_line.lastchar;
554
555 terminal__flush(el);
556
557 while ((num = (*el->el_read.read_char)(el, cp)) == 1) {
558 /* make sure there is space next character */
559 if (cp + 1 >= el->el_line.limit) {
560 idx = (size_t)(cp - el->el_line.buffer);
561 if (!ch_enlargebufs(el, (size_t)2))
562 break;
563 cp = &el->el_line.buffer[idx];
564 }
565 cp++;
566 crlf = cp[-1] == '\r' || cp[-1] == '\n';
567 if (el->el_flags & UNBUFFERED)
568 break;
569 if (crlf)
570 break;
571 }
572
573 if (num == -1) {
574 if (errno == EINTR)
575 cp = el->el_line.buffer;
576 el->el_errno = errno;
577 }
578
579 goto noedit;
580 }
581
582 for (num = OKCMD; num == OKCMD;) { /* while still editing this
583 * line */
584 #ifdef DEBUG_EDIT
585 read_debug(el);
586 #endif /* DEBUG_EDIT */
587 /* if EOF or error */
588 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
589 num = -1;
590 #ifdef DEBUG_READ
591 (void) fprintf(el->el_errfile,
592 "Returning from el_gets %d\n", num);
593 #endif /* DEBUG_READ */
594 break;
595 }
596 if (el->el_errno == EINTR) {
597 el->el_line.buffer[0] = '\0';
598 el->el_line.lastchar =
599 el->el_line.cursor = el->el_line.buffer;
600 break;
601 }
602 if ((size_t)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */
603 #ifdef DEBUG_EDIT
604 (void) fprintf(el->el_errfile,
605 "ERROR: illegal command from key 0%o\r\n", ch);
606 #endif /* DEBUG_EDIT */
607 continue; /* try again */
608 }
609 /* now do the real command */
610 #ifdef DEBUG_READ
611 {
612 el_bindings_t *b;
613 for (b = el->el_map.help; b->name; b++)
614 if (b->func == cmdnum)
615 break;
616 if (b->name)
617 (void) fprintf(el->el_errfile,
618 "Executing %s\n", b->name);
619 else
620 (void) fprintf(el->el_errfile,
621 "Error command = %d\n", cmdnum);
622 }
623 #endif /* DEBUG_READ */
624 /* vi redo needs these way down the levels... */
625 el->el_state.thiscmd = cmdnum;
626 el->el_state.thisch = ch;
627 if (el->el_map.type == MAP_VI &&
628 el->el_map.current == el->el_map.key &&
629 el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
630 if (cmdnum == VI_DELETE_PREV_CHAR &&
631 el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
632 && Isprint(el->el_chared.c_redo.pos[-1]))
633 el->el_chared.c_redo.pos--;
634 else
635 *el->el_chared.c_redo.pos++ = ch;
636 }
637 retval = (*el->el_map.func[cmdnum]) (el, ch);
638 #ifdef DEBUG_READ
639 (void) fprintf(el->el_errfile,
640 "Returned state %d\n", retval );
641 #endif /* DEBUG_READ */
642
643 /* save the last command here */
644 el->el_state.lastcmd = cmdnum;
645
646 /* use any return value */
647 switch (retval) {
648 case CC_CURSOR:
649 re_refresh_cursor(el);
650 break;
651
652 case CC_REDISPLAY:
653 re_clear_lines(el);
654 re_clear_display(el);
655 /* FALLTHROUGH */
656
657 case CC_REFRESH:
658 re_refresh(el);
659 break;
660
661 case CC_REFRESH_BEEP:
662 re_refresh(el);
663 terminal_beep(el);
664 break;
665
666 case CC_NORM: /* normal char */
667 break;
668
669 case CC_ARGHACK: /* Suggested by Rich Salz */
670 /* <rsalz@pineapple.bbn.com> */
671 continue; /* keep going... */
672
673 case CC_EOF: /* end of file typed */
674 if ((el->el_flags & UNBUFFERED) == 0)
675 num = 0;
676 else if (num == -1) {
677 *el->el_line.lastchar++ = CONTROL('d');
678 el->el_line.cursor = el->el_line.lastchar;
679 num = 1;
680 }
681 break;
682
683 case CC_NEWLINE: /* normal end of line */
684 num = (int)(el->el_line.lastchar - el->el_line.buffer);
685 break;
686
687 case CC_FATAL: /* fatal error, reset to known state */
688 #ifdef DEBUG_READ
689 (void) fprintf(el->el_errfile,
690 "*** editor fatal ERROR ***\r\n\n");
691 #endif /* DEBUG_READ */
692 /* put (real) cursor in a known place */
693 re_clear_display(el); /* reset the display stuff */
694 ch_reset(el, 1); /* reset the input pointers */
695 re_refresh(el); /* print the prompt again */
696 break;
697
698 case CC_ERROR:
699 default: /* functions we don't know about */
700 #ifdef DEBUG_READ
701 (void) fprintf(el->el_errfile,
702 "*** editor ERROR ***\r\n\n");
703 #endif /* DEBUG_READ */
704 terminal_beep(el);
705 terminal__flush(el);
706 break;
707 }
708 el->el_state.argument = 1;
709 el->el_state.doingarg = 0;
710 el->el_chared.c_vcmd.action = NOP;
711 if (el->el_flags & UNBUFFERED)
712 break;
713 }
714
715 terminal__flush(el); /* flush any buffered output */
716 /* make sure the tty is set up correctly */
717 if ((el->el_flags & UNBUFFERED) == 0) {
718 read_finish(el);
719 *nread = num != -1 ? num : 0;
720 } else {
721 *nread = (int)(el->el_line.lastchar - el->el_line.buffer);
722 }
723 goto done;
724 noedit:
725 el->el_line.cursor = el->el_line.lastchar = cp;
726 *cp = '\0';
727 *nread = (int)(el->el_line.cursor - el->el_line.buffer);
728 done:
729 if (*nread == 0) {
730 if (num == -1) {
731 *nread = -1;
732 errno = el->el_errno;
733 }
734 return NULL;
735 } else
736 return el->el_line.buffer;
737 }
738