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