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