clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cmdbuf.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/less/less/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/less/less/.. -D SYSDIR="/etc" -D HELPDIR="/usr/share/misc" -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/less/less/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/less/less/../cmdbuf.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | #include <sys/stat.h> |
18 | |
19 | #include "charset.h" |
20 | #include "cmd.h" |
21 | #include "less.h" |
22 | |
23 | extern int secure; |
24 | extern int sc_width; |
25 | extern int utf_mode; |
26 | |
27 | static char cmdbuf[CMDBUF_SIZE]; |
28 | static int cmd_col; |
29 | static int prompt_col; |
30 | static char *cp; |
31 | static int cmd_offset; |
32 | static int literal; |
33 | static int updown_match = -1; |
34 | |
35 | static int cmd_complete(int); |
36 | |
37 | |
38 | |
39 | static int in_completion = 0; |
40 | static char *tk_text; |
41 | static char *tk_original; |
42 | static char *tk_ipoint; |
43 | static char *tk_trial; |
44 | static struct textlist tk_tlist; |
45 | |
46 | static int cmd_left(void); |
47 | static int cmd_right(void); |
48 | |
49 | char openquote = '"'; |
50 | char closequote = '"'; |
51 | |
52 | |
53 | #define HISTFILE_FIRST_LINE ".less-history-file:" |
54 | #define HISTFILE_SEARCH_SECTION ".search" |
55 | #define HISTFILE_SHELL_SECTION ".shell" |
56 | |
57 | |
58 | |
59 | |
60 | struct mlist { |
61 | struct mlist *next; |
62 | struct mlist *prev; |
63 | struct mlist *curr_mp; |
64 | char *string; |
65 | int modified; |
66 | }; |
67 | |
68 | |
69 | |
70 | |
71 | struct mlist mlist_search = |
72 | { &mlist_search, &mlist_search, &mlist_search, NULL, 0 }; |
73 | void * const ml_search = (void *) &mlist_search; |
74 | |
75 | struct mlist mlist_examine = |
76 | { &mlist_examine, &mlist_examine, &mlist_examine, NULL, 0 }; |
77 | void * const ml_examine = (void *) &mlist_examine; |
78 | |
79 | struct mlist mlist_shell = |
80 | { &mlist_shell, &mlist_shell, &mlist_shell, NULL, 0 }; |
81 | void * const ml_shell = (void *) &mlist_shell; |
82 | |
83 | |
84 | |
85 | |
86 | static struct mlist *curr_mlist = NULL; |
87 | static int curr_cmdflags; |
88 | |
89 | static char cmd_mbc_buf[MAX_UTF_CHAR_LEN]; |
90 | static int cmd_mbc_buf_len; |
91 | static int cmd_mbc_buf_index; |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | void |
98 | cmd_reset(void) |
99 | { |
100 | cp = cmdbuf; |
101 | *cp = '\0'; |
102 | cmd_col = 0; |
103 | cmd_offset = 0; |
104 | literal = 0; |
105 | cmd_mbc_buf_len = 0; |
106 | updown_match = -1; |
107 | } |
108 | |
109 | |
110 | |
111 | |
112 | void |
113 | clear_cmd(void) |
114 | { |
115 | cmd_col = prompt_col = 0; |
116 | cmd_mbc_buf_len = 0; |
117 | updown_match = -1; |
118 | } |
119 | |
120 | |
121 | |
122 | |
123 | |
124 | void |
125 | cmd_putstr(char *s) |
126 | { |
127 | while (*s != '\0') { |
128 | putchr(*s++); |
129 | cmd_col++; |
130 | prompt_col++; |
131 | } |
132 | } |
133 | |
134 | |
135 | |
136 | |
137 | int |
138 | len_cmdbuf(void) |
139 | { |
140 | char *s = cmdbuf; |
141 | char *endline = s + strlen(s); |
142 | int len = 0; |
143 | |
144 | while (*s != '\0') { |
145 | step_char(&s, +1, endline); |
146 | len++; |
147 | } |
148 | return (len); |
149 | } |
150 | |
151 | |
152 | |
153 | |
154 | static char * |
155 | cmd_step_common(char *p, LWCHAR ch, int len, int *pwidth, int *bswidth) |
156 | { |
157 | char *pr; |
158 | |
159 | if (len == 1) { |
160 | pr = prchar((int)ch); |
161 | if (pwidth != NULL || bswidth != NULL) { |
162 | int prlen = strlen(pr); |
163 | if (pwidth != NULL) |
164 | *pwidth = prlen; |
165 | if (bswidth != NULL) |
166 | *bswidth = prlen; |
167 | } |
168 | } else { |
169 | pr = prutfchar(ch); |
170 | if (pwidth != NULL || bswidth != NULL) { |
171 | if (is_composing_char(ch)) { |
172 | if (pwidth != NULL) |
173 | *pwidth = 0; |
174 | if (bswidth != NULL) |
175 | *bswidth = 0; |
176 | } else if (is_ubin_char(ch)) { |
177 | int prlen = strlen(pr); |
178 | if (pwidth != NULL) |
179 | *pwidth = prlen; |
180 | if (bswidth != NULL) |
181 | *bswidth = prlen; |
182 | } else { |
183 | if (pwidth != NULL) |
184 | *pwidth = is_wide_char(ch) ? 2 : 1; |
185 | if (bswidth != NULL) |
186 | *bswidth = 1; |
187 | } |
188 | } |
189 | } |
190 | |
191 | return (pr); |
192 | } |
193 | |
194 | |
195 | |
196 | |
197 | static char * |
198 | cmd_step_right(char **pp, int *pwidth, int *bswidth) |
199 | { |
200 | char *p = *pp; |
201 | LWCHAR ch = step_char(pp, +1, p + strlen(p)); |
202 | |
203 | return (cmd_step_common(p, ch, *pp - p, pwidth, bswidth)); |
204 | } |
205 | |
206 | |
207 | |
208 | |
209 | static char * |
210 | cmd_step_left(char **pp, int *pwidth, int *bswidth) |
211 | { |
212 | char *p = *pp; |
213 | LWCHAR ch = step_char(pp, -1, cmdbuf); |
214 | |
215 | return (cmd_step_common(*pp, ch, p - *pp, pwidth, bswidth)); |
216 | } |
217 | |
218 | |
219 | |
220 | |
221 | |
222 | static void |
223 | cmd_repaint(char *old_cp) |
224 | { |
225 | |
226 | |
227 | |
228 | clear_eol(); |
229 | while (*cp != '\0') { |
230 | char *np = cp; |
231 | int width; |
232 | char *pr = cmd_step_right(&np, &width, NULL); |
233 | if (cmd_col + width >= sc_width) |
234 | break; |
235 | cp = np; |
236 | putstr(pr); |
237 | cmd_col += width; |
238 | } |
239 | while (*cp != '\0') { |
240 | char *np = cp; |
241 | int width; |
242 | char *pr = cmd_step_right(&np, &width, NULL); |
243 | if (width > 0) |
244 | break; |
245 | cp = np; |
246 | putstr(pr); |
247 | } |
248 | |
249 | |
250 | |
251 | |
252 | while (cp > old_cp) |
253 | cmd_left(); |
254 | } |
255 | |
256 | |
257 | |
258 | |
259 | |
260 | static void |
261 | cmd_home(void) |
262 | { |
263 | while (cmd_col > prompt_col) { |
264 | int width, bswidth; |
265 | |
266 | cmd_step_left(&cp, &width, &bswidth); |
267 | while (bswidth-- > 0) |
268 | putbs(); |
269 | cmd_col -= width; |
270 | } |
271 | |
272 | cp = &cmdbuf[cmd_offset]; |
273 | } |
274 | |
275 | |
276 | |
277 | |
278 | static void |
279 | cmd_lshift(void) |
280 | { |
281 | char *s; |
282 | char *save_cp; |
283 | int cols; |
284 | |
285 | |
286 | |
287 | |
288 | |
289 | s = cmdbuf + cmd_offset; |
290 | cols = 0; |
291 | while (cols < (sc_width - prompt_col) / 2 && *s != '\0') { |
292 | int width; |
293 | cmd_step_right(&s, &width, NULL); |
294 | cols += width; |
295 | } |
296 | while (*s != '\0') { |
297 | int width; |
298 | char *ns = s; |
299 | cmd_step_right(&ns, &width, NULL); |
300 | if (width > 0) |
301 | break; |
302 | s = ns; |
303 | } |
304 | |
305 | cmd_offset = s - cmdbuf; |
306 | save_cp = cp; |
307 | cmd_home(); |
308 | cmd_repaint(save_cp); |
309 | } |
310 | |
311 | |
312 | |
313 | |
314 | static void |
315 | cmd_rshift(void) |
316 | { |
317 | char *s; |
318 | char *save_cp; |
319 | int cols; |
320 | |
321 | |
322 | |
323 | |
324 | |
325 | |
326 | s = cmdbuf + cmd_offset; |
327 | cols = 0; |
328 | while (cols < (sc_width - prompt_col) / 2 && s > cmdbuf) { |
329 | int width; |
330 | cmd_step_left(&s, &width, NULL); |
331 | cols += width; |
332 | } |
333 | |
334 | cmd_offset = s - cmdbuf; |
335 | save_cp = cp; |
336 | cmd_home(); |
337 | cmd_repaint(save_cp); |
338 | } |
339 | |
340 | |
341 | |
342 | |
343 | static int |
344 | cmd_right(void) |
345 | { |
346 | char *pr; |
347 | char *ncp; |
348 | int width; |
349 | |
350 | if (*cp == '\0') { |
351 | |
352 | return (CC_OK); |
353 | } |
354 | ncp = cp; |
355 | pr = cmd_step_right(&ncp, &width, NULL); |
356 | if (cmd_col + width >= sc_width) |
357 | cmd_lshift(); |
358 | else if (cmd_col + width == sc_width - 1 && cp[1] != '\0') |
359 | cmd_lshift(); |
360 | cp = ncp; |
361 | cmd_col += width; |
362 | putstr(pr); |
363 | while (*cp != '\0') { |
364 | pr = cmd_step_right(&ncp, &width, NULL); |
365 | if (width > 0) |
366 | break; |
367 | putstr(pr); |
368 | cp = ncp; |
369 | } |
370 | return (CC_OK); |
371 | } |
372 | |
373 | |
374 | |
375 | |
376 | static int |
377 | cmd_left(void) |
378 | { |
379 | char *ncp; |
380 | int width, bswidth; |
| 20 | | 'width' declared without an initial value | |
|
381 | |
382 | if (cp <= cmdbuf) { |
| 21 | | Assuming 'cp' is > 'cmdbuf' | |
|
| |
383 | |
384 | return (CC_OK); |
385 | } |
386 | ncp = cp; |
387 | while (ncp > cmdbuf) { |
| 23 | | Loop condition is false. Execution continues on line 392 | |
|
388 | cmd_step_left(&ncp, &width, &bswidth); |
389 | if (width > 0) |
390 | break; |
391 | } |
392 | if (cmd_col < prompt_col + width) |
| 24 | | The right operand of '+' is a garbage value |
|
393 | cmd_rshift(); |
394 | cp = ncp; |
395 | cmd_col -= width; |
396 | while (bswidth-- > 0) |
397 | putbs(); |
398 | return (CC_OK); |
399 | } |
400 | |
401 | |
402 | |
403 | |
404 | static int |
405 | cmd_ichar(char *cs, int clen) |
406 | { |
407 | char *s; |
408 | |
409 | if (strlen(cmdbuf) + clen >= sizeof (cmdbuf)-1) { |
410 | |
411 | ring_bell(); |
412 | return (CC_ERROR); |
413 | } |
414 | |
415 | |
416 | |
417 | |
418 | for (s = &cmdbuf[strlen(cmdbuf)]; s >= cp; s--) |
419 | s[clen] = s[0]; |
420 | |
421 | |
422 | |
423 | for (s = cp; s < cp + clen; s++) |
424 | *s = *cs++; |
425 | |
426 | |
427 | |
428 | updown_match = -1; |
429 | cmd_repaint(cp); |
430 | cmd_right(); |
431 | return (CC_OK); |
432 | } |
433 | |
434 | |
435 | |
436 | |
437 | |
438 | static int |
439 | cmd_erase(void) |
440 | { |
441 | char *s; |
442 | int clen; |
443 | |
444 | if (cp == cmdbuf) { |
445 | |
446 | |
447 | |
448 | |
449 | return (CC_QUIT); |
450 | } |
451 | |
452 | |
453 | |
454 | s = cp; |
455 | cmd_left(); |
456 | clen = s - cp; |
457 | |
458 | |
459 | |
460 | |
461 | for (s = cp; ; s++) { |
462 | s[0] = s[clen]; |
463 | if (s[0] == '\0') |
464 | break; |
465 | } |
466 | |
467 | |
468 | |
469 | |
470 | updown_match = -1; |
471 | cmd_repaint(cp); |
472 | |
473 | |
474 | |
475 | |
476 | |
477 | if ((curr_cmdflags & CF_QUIT_ON_ERASE) && cp == cmdbuf && *cp == '\0') |
478 | return (CC_QUIT); |
479 | return (CC_OK); |
480 | } |
481 | |
482 | |
483 | |
484 | |
485 | static int |
486 | cmd_delete(void) |
487 | { |
488 | if (*cp == '\0') { |
489 | |
490 | return (CC_OK); |
491 | } |
492 | |
493 | |
494 | |
495 | cmd_right(); |
496 | cmd_erase(); |
497 | return (CC_OK); |
498 | } |
499 | |
500 | |
501 | |
502 | |
503 | static int |
504 | cmd_werase(void) |
505 | { |
506 | if (cp > cmdbuf && cp[-1] == ' ') { |
507 | |
508 | |
509 | |
510 | |
511 | while (cp > cmdbuf && cp[-1] == ' ') |
512 | (void) cmd_erase(); |
513 | } else { |
514 | |
515 | |
516 | |
517 | |
518 | while (cp > cmdbuf && cp[-1] != ' ') |
519 | (void) cmd_erase(); |
520 | } |
521 | return (CC_OK); |
522 | } |
523 | |
524 | |
525 | |
526 | |
527 | static int |
528 | cmd_wdelete(void) |
529 | { |
530 | if (*cp == ' ') { |
531 | |
532 | |
533 | |
534 | |
535 | while (*cp == ' ') |
536 | (void) cmd_delete(); |
537 | } else { |
538 | |
539 | |
540 | |
541 | |
542 | while (*cp != ' ' && *cp != '\0') |
543 | (void) cmd_delete(); |
544 | } |
545 | return (CC_OK); |
546 | } |
547 | |
548 | |
549 | |
550 | |
551 | static int |
552 | cmd_kill(void) |
553 | { |
554 | if (cmdbuf[0] == '\0') { |
555 | |
556 | return (CC_QUIT); |
557 | } |
558 | cmd_offset = 0; |
559 | cmd_home(); |
560 | *cp = '\0'; |
561 | updown_match = -1; |
562 | cmd_repaint(cp); |
563 | |
564 | |
565 | |
566 | |
567 | |
568 | if (curr_cmdflags & CF_QUIT_ON_ERASE) |
569 | return (CC_QUIT); |
570 | return (CC_OK); |
571 | } |
572 | |
573 | |
574 | |
575 | |
576 | void |
577 | set_mlist(void *mlist, int cmdflags) |
578 | { |
579 | curr_mlist = (struct mlist *)mlist; |
580 | curr_cmdflags = cmdflags; |
581 | |
582 | |
583 | if (curr_mlist != NULL) |
584 | curr_mlist->curr_mp = curr_mlist; |
585 | } |
586 | |
587 | |
588 | |
589 | |
590 | |
591 | |
592 | static int |
593 | cmd_updown(int action) |
594 | { |
595 | char *s; |
596 | struct mlist *ml; |
597 | |
598 | if (curr_mlist == NULL) { |
599 | |
600 | |
601 | |
602 | ring_bell(); |
603 | return (CC_OK); |
604 | } |
605 | |
606 | if (updown_match < 0) { |
607 | updown_match = cp - cmdbuf; |
608 | } |
609 | |
610 | |
611 | |
612 | |
613 | for (ml = curr_mlist->curr_mp; ; ) { |
614 | ml = (action == EC_UP) ? ml->prev : ml->next; |
615 | if (ml == curr_mlist) { |
616 | |
617 | |
618 | |
619 | break; |
620 | } |
621 | if (strncmp(cmdbuf, ml->string, updown_match) == 0) { |
622 | |
623 | |
624 | |
625 | |
626 | curr_mlist->curr_mp = ml; |
627 | s = ml->string; |
628 | if (s == NULL) |
629 | s = ""; |
630 | cmd_home(); |
631 | clear_eol(); |
632 | strlcpy(cmdbuf, s, sizeof (cmdbuf)); |
633 | for (cp = cmdbuf; *cp != '\0'; ) |
634 | cmd_right(); |
635 | return (CC_OK); |
636 | } |
637 | } |
638 | |
639 | |
640 | |
641 | ring_bell(); |
642 | return (CC_OK); |
643 | } |
644 | |
645 | |
646 | |
647 | |
648 | void |
649 | cmd_addhist(struct mlist *mlist, const char *cmd) |
650 | { |
651 | struct mlist *ml; |
652 | |
653 | |
654 | |
655 | |
656 | if (strlen(cmd) == 0) |
657 | return; |
658 | |
659 | |
660 | |
661 | |
662 | |
663 | ml = mlist->prev; |
664 | if (ml == mlist || strcmp(ml->string, cmd) != 0) { |
665 | |
666 | |
667 | |
668 | |
669 | ml = ecalloc(1, sizeof (struct mlist)); |
670 | ml->string = estrdup(cmd); |
671 | ml->next = mlist; |
672 | ml->prev = mlist->prev; |
673 | mlist->prev->next = ml; |
674 | mlist->prev = ml; |
675 | } |
676 | |
677 | |
678 | |
679 | |
680 | mlist->curr_mp = ml->next; |
681 | } |
682 | |
683 | |
684 | |
685 | |
686 | |
687 | void |
688 | cmd_accept(void) |
689 | { |
690 | |
691 | |
692 | |
693 | if (curr_mlist == NULL) |
694 | return; |
695 | cmd_addhist(curr_mlist, cmdbuf); |
696 | curr_mlist->modified = 1; |
697 | } |
698 | |
699 | |
700 | |
701 | |
702 | |
703 | |
704 | |
705 | |
706 | |
707 | static int |
708 | cmd_edit(int c) |
709 | { |
710 | int action; |
711 | int flags; |
712 | |
713 | #define not_in_completion() in_completion = 0 |
714 | |
715 | |
716 | |
717 | |
718 | flags = 0; |
719 | if (curr_mlist == NULL) |
| 14 | | Assuming 'curr_mlist' is not equal to NULL | |
|
| |
720 | |
721 | |
722 | |
723 | flags |= EC_NOHISTORY; |
724 | if (curr_mlist == ml_search) |
| 16 | | Assuming 'curr_mlist' is not equal to 'ml_search' | |
|
| |
725 | |
726 | |
727 | |
728 | flags |= EC_NOCOMPLETE; |
729 | |
730 | action = editchar(c, flags); |
731 | |
732 | switch (action) { |
| 18 | | Control jumps to 'case 4:' at line 736 | |
|
733 | case EC_RIGHT: |
734 | not_in_completion(); |
735 | return (cmd_right()); |
736 | case EC_LEFT: |
737 | not_in_completion(); |
738 | return (cmd_left()); |
| |
739 | case EC_W_RIGHT: |
740 | not_in_completion(); |
741 | while (*cp != '\0' && *cp != ' ') |
742 | cmd_right(); |
743 | while (*cp == ' ') |
744 | cmd_right(); |
745 | return (CC_OK); |
746 | case EC_W_LEFT: |
747 | not_in_completion(); |
748 | while (cp > cmdbuf && cp[-1] == ' ') |
749 | cmd_left(); |
750 | while (cp > cmdbuf && cp[-1] != ' ') |
751 | cmd_left(); |
752 | return (CC_OK); |
753 | case EC_HOME: |
754 | not_in_completion(); |
755 | cmd_offset = 0; |
756 | cmd_home(); |
757 | cmd_repaint(cp); |
758 | return (CC_OK); |
759 | case EC_END: |
760 | not_in_completion(); |
761 | while (*cp != '\0') |
762 | cmd_right(); |
763 | return (CC_OK); |
764 | case EC_INSERT: |
765 | not_in_completion(); |
766 | return (CC_OK); |
767 | case EC_BACKSPACE: |
768 | not_in_completion(); |
769 | return (cmd_erase()); |
770 | case EC_LINEKILL: |
771 | not_in_completion(); |
772 | return (cmd_kill()); |
773 | case EC_ABORT: |
774 | not_in_completion(); |
775 | (void) cmd_kill(); |
776 | return (CC_QUIT); |
777 | case EC_W_BACKSPACE: |
778 | not_in_completion(); |
779 | return (cmd_werase()); |
780 | case EC_DELETE: |
781 | not_in_completion(); |
782 | return (cmd_delete()); |
783 | case EC_W_DELETE: |
784 | not_in_completion(); |
785 | return (cmd_wdelete()); |
786 | case EC_LITERAL: |
787 | literal = 1; |
788 | return (CC_OK); |
789 | case EC_UP: |
790 | case EC_DOWN: |
791 | not_in_completion(); |
792 | return (cmd_updown(action)); |
793 | case EC_F_COMPLETE: |
794 | case EC_B_COMPLETE: |
795 | case EC_EXPAND: |
796 | return (cmd_complete(action)); |
797 | case EC_NOACTION: |
798 | return (CC_OK); |
799 | default: |
800 | not_in_completion(); |
801 | return (CC_PASS); |
802 | } |
803 | } |
804 | |
805 | |
806 | |
807 | |
808 | static int |
809 | cmd_istr(char *str) |
810 | { |
811 | char *s; |
812 | int action; |
813 | char *endline = str + strlen(str); |
814 | |
815 | for (s = str; *s != '\0'; ) { |
816 | char *os = s; |
817 | step_char(&s, +1, endline); |
818 | action = cmd_ichar(os, s - os); |
819 | if (action != CC_OK) { |
820 | ring_bell(); |
821 | return (action); |
822 | } |
823 | } |
824 | return (CC_OK); |
825 | } |
826 | |
827 | |
828 | |
829 | |
830 | |
831 | |
832 | |
833 | static char * |
834 | delimit_word(void) |
835 | { |
836 | char *word; |
837 | char *p; |
838 | int delim_quoted = 0; |
839 | int meta_quoted = 0; |
840 | char *esc = get_meta_escape(); |
841 | int esclen = strlen(esc); |
842 | |
843 | |
844 | |
845 | |
846 | if (*cp != ' ' && *cp != '\0') { |
847 | |
848 | |
849 | |
850 | |
851 | while (*cp != ' ' && *cp != '\0') |
852 | cmd_right(); |
853 | } |
854 | |
855 | |
856 | |
857 | |
858 | if (cp == cmdbuf) |
859 | return (NULL); |
860 | |
861 | |
862 | |
863 | |
864 | |
865 | for (word = cmdbuf; word < cp; word++) |
866 | if (*word != ' ') |
867 | break; |
868 | if (word >= cp) |
869 | return (cp); |
870 | for (p = cmdbuf; p < cp; p++) { |
871 | if (meta_quoted) { |
872 | meta_quoted = 0; |
873 | } else if (esclen > 0 && p + esclen < cp && |
874 | strncmp(p, esc, esclen) == 0) { |
875 | meta_quoted = 1; |
876 | p += esclen - 1; |
877 | } else if (delim_quoted) { |
878 | if (*p == closequote) |
879 | delim_quoted = 0; |
880 | } else { |
881 | if (*p == openquote) |
882 | delim_quoted = 1; |
883 | else if (*p == ' ') |
884 | word = p+1; |
885 | } |
886 | } |
887 | return (word); |
888 | } |
889 | |
890 | |
891 | |
892 | |
893 | |
894 | |
895 | static void |
896 | init_compl(void) |
897 | { |
898 | char *word; |
899 | char c; |
900 | |
901 | free(tk_text); |
902 | tk_text = NULL; |
903 | |
904 | |
905 | |
906 | word = delimit_word(); |
907 | if (word == NULL) |
908 | return; |
909 | |
910 | |
911 | |
912 | |
913 | tk_ipoint = word; |
914 | |
915 | |
916 | |
917 | free(tk_original); |
918 | tk_original = ecalloc(cp-word+1, sizeof (char)); |
919 | (void) strncpy(tk_original, word, cp-word); |
920 | |
921 | |
922 | |
923 | |
924 | |
925 | c = *cp; |
926 | *cp = '\0'; |
927 | if (*word != openquote) { |
928 | tk_text = fcomplete(word); |
929 | } else { |
930 | char *qword = shell_quote(word+1); |
931 | if (qword == NULL) |
932 | tk_text = fcomplete(word+1); |
933 | else |
934 | tk_text = fcomplete(qword); |
935 | free(qword); |
936 | } |
937 | *cp = c; |
938 | } |
939 | |
940 | |
941 | |
942 | |
943 | static char * |
944 | next_compl(int action, char *prev) |
945 | { |
946 | switch (action) { |
947 | case EC_F_COMPLETE: |
948 | return (forw_textlist(&tk_tlist, prev)); |
949 | case EC_B_COMPLETE: |
950 | return (back_textlist(&tk_tlist, prev)); |
951 | } |
952 | |
953 | return ("?"); |
954 | } |
955 | |
956 | |
957 | |
958 | |
959 | |
960 | |
961 | |
962 | static int |
963 | cmd_complete(int action) |
964 | { |
965 | char *s; |
966 | |
967 | if (!in_completion || action == EC_EXPAND) { |
968 | |
969 | |
970 | |
971 | |
972 | |
973 | init_compl(); |
974 | if (tk_text == NULL) { |
975 | ring_bell(); |
976 | return (CC_OK); |
977 | } |
978 | if (action == EC_EXPAND) { |
979 | |
980 | |
981 | |
982 | tk_trial = tk_text; |
983 | } else { |
984 | |
985 | |
986 | |
987 | in_completion = 1; |
988 | init_textlist(&tk_tlist, tk_text); |
989 | tk_trial = next_compl(action, NULL); |
990 | } |
991 | } else { |
992 | |
993 | |
994 | |
995 | |
996 | tk_trial = next_compl(action, tk_trial); |
997 | } |
998 | |
999 | |
1000 | |
1001 | |
1002 | while (cp > tk_ipoint) |
1003 | (void) cmd_erase(); |
1004 | |
1005 | if (tk_trial == NULL) { |
1006 | |
1007 | |
1008 | |
1009 | |
1010 | in_completion = 0; |
1011 | if (cmd_istr(tk_original) != CC_OK) |
1012 | goto fail; |
1013 | } else { |
1014 | |
1015 | |
1016 | |
1017 | if (cmd_istr(tk_trial) != CC_OK) |
1018 | goto fail; |
1019 | |
1020 | |
1021 | |
1022 | if (is_dir(tk_trial)) { |
1023 | if (cp > cmdbuf && cp[-1] == closequote) |
1024 | (void) cmd_erase(); |
1025 | s = lgetenv("LESSSEPARATOR"); |
1026 | if (s == NULL) |
1027 | s = "/"; |
1028 | if (cmd_istr(s) != CC_OK) |
1029 | goto fail; |
1030 | } |
1031 | } |
1032 | |
1033 | return (CC_OK); |
1034 | |
1035 | fail: |
1036 | in_completion = 0; |
1037 | ring_bell(); |
1038 | return (CC_OK); |
1039 | } |
1040 | |
1041 | |
1042 | |
1043 | |
1044 | |
1045 | |
1046 | |
1047 | |
1048 | |
1049 | int |
1050 | cmd_char(int c) |
1051 | { |
1052 | int action; |
1053 | int len; |
1054 | |
1055 | if (!utf_mode) { |
| 1 | Assuming 'utf_mode' is not equal to 0 | |
|
| |
1056 | cmd_mbc_buf[0] = c & 0xff; |
1057 | len = 1; |
1058 | } else { |
1059 | |
1060 | if (cmd_mbc_buf_len == 0) { |
| 3 | | Assuming 'cmd_mbc_buf_len' is not equal to 0 | |
|
| |
1061 | retry: |
1062 | cmd_mbc_buf_index = 1; |
1063 | *cmd_mbc_buf = c & 0xff; |
1064 | if (isascii((unsigned char)c)) |
| |
1065 | cmd_mbc_buf_len = 1; |
1066 | else if (IS_UTF8_LEAD(c)) { |
1067 | cmd_mbc_buf_len = utf_len(c); |
1068 | return (CC_OK); |
1069 | } else { |
1070 | |
1071 | ring_bell(); |
1072 | return (CC_ERROR); |
1073 | } |
1074 | } else if (IS_UTF8_TRAIL(c)) { |
| 5 | | Assuming the condition is false | |
|
| |
1075 | cmd_mbc_buf[cmd_mbc_buf_index++] = c & 0xff; |
1076 | if (cmd_mbc_buf_index < cmd_mbc_buf_len) |
1077 | return (CC_OK); |
1078 | if (!is_utf8_well_formed(cmd_mbc_buf)) { |
1079 | |
1080 | |
1081 | |
1082 | |
1083 | cmd_mbc_buf_len = 0; |
1084 | ring_bell(); |
1085 | return (CC_ERROR); |
1086 | } |
1087 | } else { |
1088 | |
1089 | cmd_mbc_buf_len = 0; |
1090 | ring_bell(); |
1091 | |
1092 | goto retry; |
| 7 | | Control jumps to line 1062 | |
|
1093 | } |
1094 | |
1095 | len = cmd_mbc_buf_len; |
1096 | cmd_mbc_buf_len = 0; |
1097 | } |
1098 | |
1099 | if (literal) { |
| |
| |
1100 | |
1101 | |
1102 | |
1103 | literal = 0; |
1104 | return (cmd_ichar(cmd_mbc_buf, len)); |
1105 | } |
1106 | |
1107 | |
1108 | |
1109 | |
1110 | if (in_mca() && len == 1) { |
| 11 | | Assuming the condition is true | |
|
| |
1111 | action = cmd_edit(c); |
| |
1112 | switch (action) { |
1113 | case CC_OK: |
1114 | case CC_QUIT: |
1115 | return (action); |
1116 | case CC_PASS: |
1117 | break; |
1118 | } |
1119 | } |
1120 | |
1121 | |
1122 | |
1123 | |
1124 | return (cmd_ichar(cmd_mbc_buf, len)); |
1125 | } |
1126 | |
1127 | |
1128 | |
1129 | |
1130 | off_t |
1131 | cmd_int(long *frac) |
1132 | { |
1133 | char *p; |
1134 | off_t n = 0; |
1135 | int err; |
1136 | |
1137 | for (p = cmdbuf; *p >= '0' && *p <= '9'; p++) |
1138 | n = (n * 10) + (*p - '0'); |
1139 | *frac = 0; |
1140 | if (*p++ == '.') { |
1141 | *frac = getfraction(&p, NULL, &err); |
1142 | |
1143 | } |
1144 | return (n); |
1145 | } |
1146 | |
1147 | |
1148 | |
1149 | |
1150 | char * |
1151 | get_cmdbuf(void) |
1152 | { |
1153 | return (cmdbuf); |
1154 | } |
1155 | |
1156 | |
1157 | |
1158 | |
1159 | char * |
1160 | cmd_lastpattern(void) |
1161 | { |
1162 | if (curr_mlist == NULL) |
1163 | return (NULL); |
1164 | return (curr_mlist->curr_mp->prev->string); |
1165 | } |
1166 | |
1167 | |
1168 | |
1169 | |
1170 | static char * |
1171 | histfile_name(void) |
1172 | { |
1173 | char *home; |
1174 | char *name; |
1175 | |
1176 | |
1177 | name = lgetenv("LESSHISTFILE"); |
1178 | if (name != NULL && *name != '\0') { |
1179 | if (strcmp(name, "-") == 0 || strcmp(name, "/dev/null") == 0) |
1180 | |
1181 | return (NULL); |
1182 | return (estrdup(name)); |
1183 | } |
1184 | |
1185 | |
1186 | if (strcmp(LESSHISTFILE, "-") == 0) |
1187 | return (NULL); |
1188 | home = lgetenv("HOME"); |
1189 | if (home == NULL || *home == '\0') { |
1190 | return (NULL); |
1191 | } |
1192 | return (easprintf("%s/%s", home, LESSHISTFILE)); |
1193 | } |
1194 | |
1195 | |
1196 | |
1197 | |
1198 | void |
1199 | init_cmdhist(void) |
1200 | { |
1201 | struct mlist *ml = NULL; |
1202 | char line[CMDBUF_SIZE]; |
1203 | char *filename; |
1204 | FILE *f; |
1205 | char *p; |
1206 | |
1207 | if (secure) |
1208 | return; |
1209 | filename = histfile_name(); |
1210 | if (filename == NULL) |
1211 | return; |
1212 | f = fopen(filename, "r"); |
1213 | free(filename); |
1214 | if (f == NULL) |
1215 | return; |
1216 | if (fgets(line, sizeof (line), f) == NULL || |
1217 | strncmp(line, HISTFILE_FIRST_LINE, |
1218 | strlen(HISTFILE_FIRST_LINE)) != 0) { |
1219 | (void) fclose(f); |
1220 | return; |
1221 | } |
1222 | while (fgets(line, sizeof (line), f) != NULL) { |
1223 | for (p = line; *p != '\0'; p++) { |
1224 | if (*p == '\n' || *p == '\r') { |
1225 | *p = '\0'; |
1226 | break; |
1227 | } |
1228 | } |
1229 | if (strcmp(line, HISTFILE_SEARCH_SECTION) == 0) |
1230 | ml = &mlist_search; |
1231 | else if (strcmp(line, HISTFILE_SHELL_SECTION) == 0) { |
1232 | ml = &mlist_shell; |
1233 | } else if (*line == '"') { |
1234 | if (ml != NULL) |
1235 | cmd_addhist(ml, line+1); |
1236 | } |
1237 | } |
1238 | (void) fclose(f); |
1239 | } |
1240 | |
1241 | |
1242 | |
1243 | |
1244 | static void |
1245 | save_mlist(struct mlist *ml, FILE *f) |
1246 | { |
1247 | int histsize = 0; |
1248 | int n; |
1249 | char *s; |
1250 | |
1251 | s = lgetenv("LESSHISTSIZE"); |
1252 | if (s != NULL) |
1253 | histsize = atoi(s); |
1254 | if (histsize == 0) |
1255 | histsize = 100; |
1256 | |
1257 | ml = ml->prev; |
1258 | for (n = 0; n < histsize; n++) { |
1259 | if (ml->string == NULL) |
1260 | break; |
1261 | ml = ml->prev; |
1262 | } |
1263 | for (ml = ml->next; ml->string != NULL; ml = ml->next) |
1264 | (void) fprintf(f, "\"%s\n", ml->string); |
1265 | } |
1266 | |
1267 | |
1268 | |
1269 | |
1270 | void |
1271 | save_cmdhist(void) |
1272 | { |
1273 | char *filename; |
1274 | FILE *f; |
1275 | int modified = 0; |
1276 | int do_chmod = 1; |
1277 | struct stat statbuf; |
1278 | int r; |
1279 | |
1280 | if (secure) |
1281 | return; |
1282 | if (mlist_search.modified) |
1283 | modified = 1; |
1284 | if (mlist_shell.modified) |
1285 | modified = 1; |
1286 | if (!modified) |
1287 | return; |
1288 | filename = histfile_name(); |
1289 | if (filename == NULL) |
1290 | return; |
1291 | f = fopen(filename, "w"); |
1292 | free(filename); |
1293 | if (f == NULL) |
1294 | return; |
1295 | |
1296 | |
1297 | r = fstat(fileno(f), &statbuf); |
1298 | if (r == -1 || !S_ISREG(statbuf.st_mode)) |
1299 | |
1300 | do_chmod = 0; |
1301 | if (do_chmod) |
1302 | (void) fchmod(fileno(f), 0600); |
1303 | |
1304 | (void) fprintf(f, "%s\n", HISTFILE_FIRST_LINE); |
1305 | |
1306 | (void) fprintf(f, "%s\n", HISTFILE_SEARCH_SECTION); |
1307 | save_mlist(&mlist_search, f); |
1308 | |
1309 | (void) fprintf(f, "%s\n", HISTFILE_SHELL_SECTION); |
1310 | save_mlist(&mlist_shell, f); |
1311 | |
1312 | (void) fclose(f); |
1313 | } |