Bug Summary

File:src/gnu/lib/libreadline/text.c
Warning:line 1094, column 7
Value stored to 'start' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name text.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 -fhalf-no-semantic-interposition -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/gnu/lib/libreadline/obj -resource-dir /usr/local/lib/clang/13.0.0 -D HAVE_CONFIG_H -I /usr/src/gnu/lib/libreadline -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/gnu/lib/libreadline/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/gnu/lib/libreadline/text.c
1/* text.c -- text handling commands for readline. */
2
3/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
4
5 This file is part of the GNU Readline Library, a library for
6 reading lines of text with interactive input and history editing.
7
8 The GNU Readline Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2, or
11 (at your option) any later version.
12
13 The GNU Readline Library is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 The GNU General Public License is often shipped with GNU software, and
19 is generally kept in a file called COPYING or LICENSE. If you do not
20 have a copy of the license, write to the Free Software Foundation,
21 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22#define READLINE_LIBRARY
23
24#if defined (HAVE_CONFIG_H1)
25# include <config.h>
26#endif
27
28#if defined (HAVE_UNISTD_H1)
29# include <unistd.h>
30#endif /* HAVE_UNISTD_H */
31
32#if defined (HAVE_STDLIB_H1)
33# include <stdlib.h>
34#else
35# include "ansi_stdlib.h"
36#endif /* HAVE_STDLIB_H */
37
38#if defined (HAVE_LOCALE_H1)
39# include <locale.h>
40#endif
41
42#include <stdio.h>
43
44/* System-specific feature definitions and include files. */
45#include "rldefs.h"
46#include "rlmbutil.h"
47
48#if defined (__EMX__)
49# define INCL_DOSPROCESS
50# include <os2.h>
51#endif /* __EMX__ */
52
53/* Some standard library routines. */
54#include "readline.h"
55#include "history.h"
56
57#include "rlprivate.h"
58#include "rlshell.h"
59#include "xmalloc.h"
60
61/* Forward declarations. */
62static int rl_change_case PARAMS((int, int))(int, int);
63static int _rl_char_search PARAMS((int, int, int))(int, int, int);
64
65/* **************************************************************** */
66/* */
67/* Insert and Delete */
68/* */
69/* **************************************************************** */
70
71/* Insert a string of text into the line at point. This is the only
72 way that you should do insertion. _rl_insert_char () calls this
73 function. Returns the number of characters inserted. */
74int
75rl_insert_text (string)
76 const char *string;
77{
78 register int i, l;
79
80 l = (string && *string) ? strlen (string) : 0;
81 if (l == 0)
82 return 0;
83
84 if (rl_end + l >= rl_line_buffer_len)
85 rl_extend_line_buffer (rl_end + l);
86
87 for (i = rl_end; i >= rl_point; i--)
88 rl_line_buffer[i + l] = rl_line_buffer[i];
89 strncpy (rl_line_buffer + rl_point, string, l);
90
91 /* Remember how to undo this if we aren't undoing something. */
92 if (_rl_doing_an_undo == 0)
93 {
94 /* If possible and desirable, concatenate the undos. */
95 if ((l == 1) &&
96 rl_undo_list &&
97 (rl_undo_list->what == UNDO_INSERT) &&
98 (rl_undo_list->end == rl_point) &&
99 (rl_undo_list->end - rl_undo_list->start < 20))
100 rl_undo_list->end++;
101 else
102 rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL((void *)0));
103 }
104 rl_point += l;
105 rl_end += l;
106 rl_line_buffer[rl_end] = '\0';
107 return l;
108}
109
110/* Delete the string between FROM and TO. FROM is inclusive, TO is not.
111 Returns the number of characters deleted. */
112int
113rl_delete_text (from, to)
114 int from, to;
115{
116 register char *text;
117 register int diff, i;
118
119 /* Fix it if the caller is confused. */
120 if (from > to)
121 SWAP (from, to)do { int t; t = from; from = to; to = t; } while (0);
122
123 /* fix boundaries */
124 if (to > rl_end)
125 {
126 to = rl_end;
127 if (from > to)
128 from = to;
129 }
130 if (from < 0)
131 from = 0;
132
133 text = rl_copy_text (from, to);
134
135 /* Some versions of strncpy() can't handle overlapping arguments. */
136 diff = to - from;
137 for (i = from; i < rl_end - diff; i++)
138 rl_line_buffer[i] = rl_line_buffer[i + diff];
139
140 /* Remember how to undo this delete. */
141 if (_rl_doing_an_undo == 0)
142 rl_add_undo (UNDO_DELETE, from, to, text);
143 else
144 free (text);
145
146 rl_end -= diff;
147 rl_line_buffer[rl_end] = '\0';
148 return (diff);
149}
150
151/* Fix up point so that it is within the line boundaries after killing
152 text. If FIX_MARK_TOO is non-zero, the mark is forced within line
153 boundaries also. */
154
155#define _RL_FIX_POINT(x) \
156 do { \
157 if (x > rl_end) \
158 x = rl_end; \
159 else if (x < 0) \
160 x = 0; \
161 } while (0)
162
163void
164_rl_fix_point (fix_mark_too)
165 int fix_mark_too;
166{
167 _RL_FIX_POINT (rl_point);
168 if (fix_mark_too)
169 _RL_FIX_POINT (rl_mark);
170}
171#undef _RL_FIX_POINT
172
173int
174_rl_replace_text (text, start, end)
175 const char *text;
176 int start, end;
177{
178 int n;
179
180 rl_begin_undo_group ();
181 rl_delete_text (start, end + 1);
182 rl_point = start;
183 n = rl_insert_text (text);
184 rl_end_undo_group ();
185
186 return n;
187}
188
189/* Replace the current line buffer contents with TEXT. If CLEAR_UNDO is
190 non-zero, we free the current undo list. */
191void
192rl_replace_line (text, clear_undo)
193 const char *text;
194 int clear_undo;
195{
196 int len;
197
198 len = strlen (text);
199 if (len >= rl_line_buffer_len)
200 rl_extend_line_buffer (len);
201 strlcpy (rl_line_buffer, text, rl_line_buffer_len);
202 rl_end = len;
203
204 if (clear_undo)
205 rl_free_undo_list ();
206
207 _rl_fix_point (1);
208}
209
210/* **************************************************************** */
211/* */
212/* Readline character functions */
213/* */
214/* **************************************************************** */
215
216/* This is not a gap editor, just a stupid line input routine. No hair
217 is involved in writing any of the functions, and none should be. */
218
219/* Note that:
220
221 rl_end is the place in the string that we would place '\0';
222 i.e., it is always safe to place '\0' there.
223
224 rl_point is the place in the string where the cursor is. Sometimes
225 this is the same as rl_end.
226
227 Any command that is called interactively receives two arguments.
228 The first is a count: the numeric arg pased to this command.
229 The second is the key which invoked this command.
230*/
231
232/* **************************************************************** */
233/* */
234/* Movement Commands */
235/* */
236/* **************************************************************** */
237
238/* Note that if you `optimize' the display for these functions, you cannot
239 use said functions in other functions which do not do optimizing display.
240 I.e., you will have to update the data base for rl_redisplay, and you
241 might as well let rl_redisplay do that job. */
242
243/* Move forward COUNT bytes. */
244int
245rl_forward_byte (count, key)
246 int count, key;
247{
248 if (count < 0)
249 return (rl_backward_byte (-count, key));
250
251 if (count > 0)
252 {
253 int end = rl_point + count;
254#if defined (VI_MODE)
255 int lend = rl_end > 0 ? rl_end - (rl_editing_mode == vi_mode0) : rl_end;
256#else
257 int lend = rl_end;
258#endif
259
260 if (end > lend)
261 {
262 rl_point = lend;
263 rl_ding ();
264 }
265 else
266 rl_point = end;
267 }
268
269 if (rl_end < 0)
270 rl_end = 0;
271
272 return 0;
273}
274
275#if defined (HANDLE_MULTIBYTE)
276/* Move forward COUNT characters. */
277int
278rl_forward_char (count, key)
279 int count, key;
280{
281 int point;
282
283 if (MB_CUR_MAX1 == 1 || rl_byte_oriented)
284 return (rl_forward_byte (count, key));
285
286 if (count < 0)
287 return (rl_backward_char (-count, key));
288
289 if (count > 0)
290 {
291 point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO)((rl_point) + (count));
292
293#if defined (VI_MODE)
294 if (rl_end <= point && rl_editing_mode == vi_mode0)
295 point = _rl_find_prev_mbchar (rl_line_buffer, rl_end, MB_FIND_NONZERO)(((rl_end) == 0) ? (rl_end) : ((rl_end) - 1));
296#endif
297
298 if (rl_point == point)
299 rl_ding ();
300
301 rl_point = point;
302
303 if (rl_end < 0)
304 rl_end = 0;
305 }
306
307 return 0;
308}
309#else /* !HANDLE_MULTIBYTE */
310int
311rl_forward_char (count, key)
312 int count, key;
313{
314 return (rl_forward_byte (count, key));
315}
316#endif /* !HANDLE_MULTIBYTE */
317
318/* Backwards compatibility. */
319int
320rl_forward (count, key)
321 int count, key;
322{
323 return (rl_forward_char (count, key));
324}
325
326/* Move backward COUNT bytes. */
327int
328rl_backward_byte (count, key)
329 int count, key;
330{
331 if (count < 0)
332 return (rl_forward_byte (-count, key));
333
334 if (count > 0)
335 {
336 if (rl_point < count)
337 {
338 rl_point = 0;
339 rl_ding ();
340 }
341 else
342 rl_point -= count;
343 }
344
345 if (rl_point < 0)
346 rl_point = 0;
347
348 return 0;
349}
350
351#if defined (HANDLE_MULTIBYTE)
352/* Move backward COUNT characters. */
353int
354rl_backward_char (count, key)
355 int count, key;
356{
357 int point;
358
359 if (MB_CUR_MAX1 == 1 || rl_byte_oriented)
360 return (rl_backward_byte (count, key));
361
362 if (count < 0)
363 return (rl_forward_char (-count, key));
364
365 if (count > 0)
366 {
367 point = rl_point;
368
369 while (count > 0 && point > 0)
370 {
371 point = _rl_find_prev_mbchar (rl_line_buffer, point, MB_FIND_NONZERO)(((point) == 0) ? (point) : ((point) - 1));
372 count--;
373 }
374 if (count > 0)
375 {
376 rl_point = 0;
377 rl_ding ();
378 }
379 else
380 rl_point = point;
381 }
382
383 return 0;
384}
385#else
386int
387rl_backward_char (count, key)
388 int count, key;
389{
390 return (rl_backward_byte (count, key));
391}
392#endif
393
394/* Backwards compatibility. */
395int
396rl_backward (count, key)
397 int count, key;
398{
399 return (rl_backward_char (count, key));
400}
401
402/* Move to the beginning of the line. */
403int
404rl_beg_of_line (count, key)
405 int count, key;
406{
407 rl_point = 0;
408 return 0;
409}
410
411/* Move to the end of the line. */
412int
413rl_end_of_line (count, key)
414 int count, key;
415{
416 rl_point = rl_end;
417 return 0;
418}
419
420/* XXX - these might need changes for multibyte characters */
421/* Move forward a word. We do what Emacs does. */
422int
423rl_forward_word (count, key)
424 int count, key;
425{
426 int c;
427
428 if (count < 0)
429 return (rl_backward_word (-count, key));
430
431 while (count)
432 {
433 if (rl_point == rl_end)
434 return 0;
435
436 /* If we are not in a word, move forward until we are in one.
437 Then, move forward until we hit a non-alphabetic character. */
438 c = rl_line_buffer[rl_point];
439 if (rl_alphabetic (c) == 0)
440 {
441 while (++rl_point < rl_end)
442 {
443 c = rl_line_buffer[rl_point];
444 if (rl_alphabetic (c))
445 break;
446 }
447 }
448
449 if (rl_point == rl_end)
450 return 0;
451
452 while (++rl_point < rl_end)
453 {
454 c = rl_line_buffer[rl_point];
455 if (rl_alphabetic (c) == 0)
456 break;
457 }
458 --count;
459 }
460
461 return 0;
462}
463
464/* Move backward a word. We do what Emacs does. */
465int
466rl_backward_word (count, key)
467 int count, key;
468{
469 int c;
470
471 if (count < 0)
472 return (rl_forward_word (-count, key));
473
474 while (count)
475 {
476 if (!rl_point)
477 return 0;
478
479 /* Like rl_forward_word (), except that we look at the characters
480 just before point. */
481
482 c = rl_line_buffer[rl_point - 1];
483 if (rl_alphabetic (c) == 0)
484 {
485 while (--rl_point)
486 {
487 c = rl_line_buffer[rl_point - 1];
488 if (rl_alphabetic (c))
489 break;
490 }
491 }
492
493 while (rl_point)
494 {
495 c = rl_line_buffer[rl_point - 1];
496 if (rl_alphabetic (c) == 0)
497 break;
498 else
499 --rl_point;
500 }
501
502 --count;
503 }
504
505 return 0;
506}
507
508/* Clear the current line. Numeric argument to C-l does this. */
509int
510rl_refresh_line (ignore1, ignore2)
511 int ignore1, ignore2;
512{
513 int curr_line;
514
515 curr_line = _rl_current_display_line ();
516
517 _rl_move_vert (curr_line);
518 _rl_move_cursor_relative (0, rl_line_buffer); /* XXX is this right */
519
520 _rl_clear_to_eol (0); /* arg of 0 means to not use spaces */
521
522 rl_forced_update_display ();
523 rl_display_fixed = 1;
524
525 return 0;
526}
527
528/* C-l typed to a line without quoting clears the screen, and then reprints
529 the prompt and the current input line. Given a numeric arg, redraw only
530 the current line. */
531int
532rl_clear_screen (count, key)
533 int count, key;
534{
535 if (rl_explicit_arg)
536 {
537 rl_refresh_line (count, key);
538 return 0;
539 }
540
541 _rl_clear_screen (); /* calls termcap function to clear screen */
542 rl_forced_update_display ();
543 rl_display_fixed = 1;
544
545 return 0;
546}
547
548int
549rl_arrow_keys (count, c)
550 int count, c;
551{
552 int ch;
553
554 RL_SETSTATE(RL_STATE_MOREINPUT)(rl_readline_state |= (0x00040));
555 ch = rl_read_key ();
556 RL_UNSETSTATE(RL_STATE_MOREINPUT)(rl_readline_state &= ~(0x00040));
557
558 switch (_rl_to_upper (ch)((((unsigned char)(ch) == (ch)) && (isascii(ch) &&
islower (ch))) ? toupper((unsigned char)ch) : (ch))
)
559 {
560 case 'A':
561 rl_get_previous_history (count, ch);
562 break;
563
564 case 'B':
565 rl_get_next_history (count, ch);
566 break;
567
568 case 'C':
569 if (MB_CUR_MAX1 > 1 && rl_byte_oriented == 0)
570 rl_forward_char (count, ch);
571 else
572 rl_forward_byte (count, ch);
573 break;
574
575 case 'D':
576 if (MB_CUR_MAX1 > 1 && rl_byte_oriented == 0)
577 rl_backward_char (count, ch);
578 else
579 rl_backward_byte (count, ch);
580 break;
581
582 default:
583 rl_ding ();
584 }
585
586 return 0;
587}
588
589/* **************************************************************** */
590/* */
591/* Text commands */
592/* */
593/* **************************************************************** */
594
595#ifdef HANDLE_MULTIBYTE
596static char pending_bytes[MB_LEN_MAX1];
597static int pending_bytes_length = 0;
598static mbstate_t ps = {0};
599#endif
600
601/* Insert the character C at the current location, moving point forward.
602 If C introduces a multibyte sequence, we read the whole sequence and
603 then insert the multibyte char into the line buffer. */
604int
605_rl_insert_char (count, c)
606 int count, c;
607{
608 register int i;
609 char *string;
610#ifdef HANDLE_MULTIBYTE
611 int string_size;
612 char incoming[MB_LEN_MAX1 + 1];
613 int incoming_length = 0;
614 mbstate_t ps_back;
615 static int stored_count = 0;
616#endif
617
618 if (count <= 0)
619 return 0;
620
621#if defined (HANDLE_MULTIBYTE)
622 if (MB_CUR_MAX1 == 1 || rl_byte_oriented)
623 {
624 incoming[0] = c;
625 incoming[1] = '\0';
626 incoming_length = 1;
627 }
628 else
629 {
630 wchar_t wc;
631 size_t ret;
632
633 if (stored_count <= 0)
634 stored_count = count;
635 else
636 count = stored_count;
637
638 ps_back = ps;
639 pending_bytes[pending_bytes_length++] = c;
640 ret = mbrtowc (&wc, pending_bytes, pending_bytes_length, &ps);
641
642 if (ret == (size_t)-2)
643 {
644 /* Bytes too short to compose character, try to wait for next byte.
645 Restore the state of the byte sequence, because in this case the
646 effect of mbstate is undefined. */
647 ps = ps_back;
648 return 1;
649 }
650 else if (ret == (size_t)-1)
651 {
652 /* Invalid byte sequence for the current locale. Treat first byte
653 as a single character. */
654 incoming[0] = pending_bytes[0];
655 incoming[1] = '\0';
656 incoming_length = 1;
657 pending_bytes_length--;
658 memmove (pending_bytes, pending_bytes + 1, pending_bytes_length);
659 /* Clear the state of the byte sequence, because in this case the
660 effect of mbstate is undefined. */
661 memset (&ps, 0, sizeof (mbstate_t));
662 }
663 else if (ret == (size_t)0)
664 {
665 incoming[0] = '\0';
666 incoming_length = 0;
667 pending_bytes_length--;
668 /* Clear the state of the byte sequence, because in this case the
669 effect of mbstate is undefined. */
670 memset (&ps, 0, sizeof (mbstate_t));
671 }
672 else
673 {
674 /* We successfully read a single multibyte character. */
675 memcpy (incoming, pending_bytes, pending_bytes_length);
676 incoming[pending_bytes_length] = '\0';
677 incoming_length = pending_bytes_length;
678 pending_bytes_length = 0;
679 }
680 }
681#endif /* HANDLE_MULTIBYTE */
682
683 /* If we can optimize, then do it. But don't let people crash
684 readline because of extra large arguments. */
685 if (count > 1 && count <= 1024)
686 {
687#if defined (HANDLE_MULTIBYTE)
688 string_size = count * incoming_length;
689 string = (char *)xmalloc (1 + string_size);
690
691 i = 0;
692 while (i < string_size)
693 {
694 strncpy (string + i, incoming, incoming_length);
695 i += incoming_length;
696 }
697 incoming_length = 0;
698 stored_count = 0;
699#else /* !HANDLE_MULTIBYTE */
700 string = (char *)xmalloc (1 + count);
701
702 for (i = 0; i < count; i++)
703 string[i] = c;
704#endif /* !HANDLE_MULTIBYTE */
705
706 string[i] = '\0';
707 rl_insert_text (string);
708 free (string);
709
710 return 0;
711 }
712
713 if (count > 1024)
714 {
715 int decreaser;
716#if defined (HANDLE_MULTIBYTE)
717 string_size = incoming_length * 1024;
718 string = (char *)xmalloc (1 + string_size);
719
720 i = 0;
721 while (i < string_size)
722 {
723 strncpy (string + i, incoming, incoming_length);
724 i += incoming_length;
725 }
726
727 while (count)
728 {
729 decreaser = (count > 1024) ? 1024 : count;
730 string[decreaser*incoming_length] = '\0';
731 rl_insert_text (string);
732 count -= decreaser;
733 }
734
735 free (string);
736 incoming_length = 0;
737 stored_count = 0;
738#else /* !HANDLE_MULTIBYTE */
739 char str[1024+1];
740
741 for (i = 0; i < 1024; i++)
742 str[i] = c;
743
744 while (count)
745 {
746 decreaser = (count > 1024 ? 1024 : count);
747 str[decreaser] = '\0';
748 rl_insert_text (str);
749 count -= decreaser;
750 }
751#endif /* !HANDLE_MULTIBYTE */
752
753 return 0;
754 }
755
756#if defined (HANDLE_MULTIBYTE)
757 if (MB_CUR_MAX1 == 1 || rl_byte_oriented)
758 {
759#endif
760 /* We are inserting a single character.
761 If there is pending input, then make a string of all of the
762 pending characters that are bound to rl_insert, and insert
763 them all. */
764 if (_rl_any_typein ())
765 _rl_insert_typein (c);
766 else
767 {
768 /* Inserting a single character. */
769 char str[2];
770
771 str[1] = '\0';
772 str[0] = c;
773 rl_insert_text (str);
774 }
775#if defined (HANDLE_MULTIBYTE)
776 }
777 else
778 {
779 rl_insert_text (incoming);
780 stored_count = 0;
781 }
782#endif
783
784 return 0;
785}
786
787/* Overwrite the character at point (or next COUNT characters) with C.
788 If C introduces a multibyte character sequence, read the entire sequence
789 before starting the overwrite loop. */
790int
791_rl_overwrite_char (count, c)
792 int count, c;
793{
794 int i;
795#if defined (HANDLE_MULTIBYTE)
796 char mbkey[MB_LEN_MAX1];
797 int k;
798
799 /* Read an entire multibyte character sequence to insert COUNT times. */
800 if (count > 0 && MB_CUR_MAX1 > 1 && rl_byte_oriented == 0)
801 k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX1);
802#endif
803
804 for (i = 0; i < count; i++)
805 {
806 rl_begin_undo_group ();
807
808 if (rl_point < rl_end)
809 rl_delete (1, c);
810
811#if defined (HANDLE_MULTIBYTE)
812 if (MB_CUR_MAX1 > 1 && rl_byte_oriented == 0)
813 rl_insert_text (mbkey);
814 else
815#endif
816 _rl_insert_char (1, c);
817
818 rl_end_undo_group ();
819 }
820
821 return 0;
822}
823
824int
825rl_insert (count, c)
826 int count, c;
827{
828 return (rl_insert_mode == RL_IM_INSERT1 ? _rl_insert_char (count, c)
829 : _rl_overwrite_char (count, c));
830}
831
832/* Insert the next typed character verbatim. */
833int
834rl_quoted_insert (count, key)
835 int count, key;
836{
837 int c;
838
839#if defined (HANDLE_SIGNALS)
840 _rl_disable_tty_signals ();
841#endif
842
843 RL_SETSTATE(RL_STATE_MOREINPUT)(rl_readline_state |= (0x00040));
844 c = rl_read_key ();
845 RL_UNSETSTATE(RL_STATE_MOREINPUT)(rl_readline_state &= ~(0x00040));
846
847#if defined (HANDLE_SIGNALS)
848 _rl_restore_tty_signals ();
849#endif
850
851 return (_rl_insert_char (count, c));
852}
853
854/* Insert a tab character. */
855int
856rl_tab_insert (count, key)
857 int count, key;
858{
859 return (_rl_insert_char (count, '\t'));
860}
861
862/* What to do when a NEWLINE is pressed. We accept the whole line.
863 KEY is the key that invoked this command. I guess it could have
864 meaning in the future. */
865int
866rl_newline (count, key)
867 int count, key;
868{
869 rl_done = 1;
870
871 if (_rl_history_preserve_point)
872 _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
873
874 RL_SETSTATE(RL_STATE_DONE)(rl_readline_state |= (0x80000));
875
876#if defined (VI_MODE)
877 if (rl_editing_mode == vi_mode0)
878 {
879 _rl_vi_done_inserting ();
880 _rl_vi_reset_last ();
881 }
882#endif /* VI_MODE */
883
884 /* If we've been asked to erase empty lines, suppress the final update,
885 since _rl_update_final calls rl_crlf(). */
886 if (rl_erase_empty_line && rl_point == 0 && rl_end == 0)
887 return 0;
888
889 if (readline_echoing_p)
890 _rl_update_final ();
891 return 0;
892}
893
894/* What to do for some uppercase characters, like meta characters,
895 and some characters appearing in emacs_ctlx_keymap. This function
896 is just a stub, you bind keys to it and the code in _rl_dispatch ()
897 is special cased. */
898int
899rl_do_lowercase_version (ignore1, ignore2)
900 int ignore1, ignore2;
901{
902 return 0;
903}
904
905/* This is different from what vi does, so the code's not shared. Emacs
906 rubout in overwrite mode has one oddity: it replaces a control
907 character that's displayed as two characters (^X) with two spaces. */
908int
909_rl_overwrite_rubout (count, key)
910 int count, key;
911{
912 int opoint;
913 int i, l;
914
915 if (rl_point == 0)
916 {
917 rl_ding ();
918 return 1;
919 }
920
921 opoint = rl_point;
922
923 /* L == number of spaces to insert */
924 for (i = l = 0; i < count; i++)
925 {
926 rl_backward_char (1, key);
927 l += rl_character_len (rl_line_buffer[rl_point], rl_point); /* not exactly right */
928 }
929
930 rl_begin_undo_group ();
931
932 if (count > 1 || rl_explicit_arg)
933 rl_kill_text (opoint, rl_point);
934 else
935 rl_delete_text (opoint, rl_point);
936
937 /* Emacs puts point at the beginning of the sequence of spaces. */
938 opoint = rl_point;
939 _rl_insert_char (l, ' ');
940 rl_point = opoint;
941
942 rl_end_undo_group ();
943
944 return 0;
945}
946
947/* Rubout the character behind point. */
948int
949rl_rubout (count, key)
950 int count, key;
951{
952 if (count < 0)
953 return (rl_delete (-count, key));
954
955 if (!rl_point)
956 {
957 rl_ding ();
958 return -1;
959 }
960
961 if (rl_insert_mode == RL_IM_OVERWRITE0)
962 return (_rl_overwrite_rubout (count, key));
963
964 return (_rl_rubout_char (count, key));
965}
966
967int
968_rl_rubout_char (count, key)
969 int count, key;
970{
971 int orig_point;
972 unsigned char c;
973
974 /* Duplicated code because this is called from other parts of the library. */
975 if (count < 0)
976 return (rl_delete (-count, key));
977
978 if (rl_point == 0)
979 {
980 rl_ding ();
981 return -1;
982 }
983
984 if (count > 1 || rl_explicit_arg)
985 {
986 orig_point = rl_point;
987#if defined (HANDLE_MULTIBYTE)
988 if (MB_CUR_MAX1 > 1 && rl_byte_oriented == 0)
989 rl_backward_char (count, key);
990 else
991#endif
992 rl_backward_byte (count, key);
993 rl_kill_text (orig_point, rl_point);
994 }
995 else
996 {
997#if defined (HANDLE_MULTIBYTE)
998 if (MB_CUR_MAX1 == 1 || rl_byte_oriented)
999 {
1000#endif
1001 c = rl_line_buffer[--rl_point];
1002 rl_delete_text (rl_point, rl_point + 1);
1003#if defined (HANDLE_MULTIBYTE)
1004 }
1005 else
1006 {
1007 int orig_point;
1008
1009 orig_point = rl_point;
1010 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO)(((rl_point) == 0) ? (rl_point) : ((rl_point) - 1));
1011 c = rl_line_buffer[rl_point];
1012 rl_delete_text (rl_point, orig_point);
1013 }
1014#endif /* HANDLE_MULTIBYTE */
1015
1016 /* I don't think that the hack for end of line is needed for
1017 multibyte chars. */
1018#if defined (HANDLE_MULTIBYTE)
1019 if (MB_CUR_MAX1 == 1 || rl_byte_oriented)
1020#endif
1021 if (rl_point == rl_end && ISPRINT (c)(isascii(c) && isprint (c)) && _rl_last_c_pos)
1022 {
1023 int l;
1024 l = rl_character_len (c, rl_point);
1025 _rl_erase_at_end_of_line (l);
1026 }
1027 }
1028
1029 return 0;
1030}
1031
1032/* Delete the character under the cursor. Given a numeric argument,
1033 kill that many characters instead. */
1034int
1035rl_delete (count, key)
1036 int count, key;
1037{
1038 int r;
1039
1040 if (count < 0)
1041 return (_rl_rubout_char (-count, key));
1042
1043 if (rl_point == rl_end)
1044 {
1045 rl_ding ();
1046 return -1;
1047 }
1048
1049 if (count > 1 || rl_explicit_arg)
1050 {
1051 int orig_point = rl_point;
1052#if defined (HANDLE_MULTIBYTE)
1053 if (MB_CUR_MAX1 > 1 && rl_byte_oriented == 0)
1054 rl_forward_char (count, key);
1055 else
1056#endif
1057 rl_forward_byte (count, key);
1058
1059 r = rl_kill_text (orig_point, rl_point);
1060 rl_point = orig_point;
1061 return r;
1062 }
1063 else
1064 {
1065 int new_point;
1066 if (MB_CUR_MAX1 > 1 && rl_byte_oriented == 0)
1067 new_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO)((rl_point) + (1));
1068 else
1069 new_point = rl_point + 1;
1070
1071 return (rl_delete_text (rl_point, new_point));
1072 }
1073}
1074
1075/* Delete the character under the cursor, unless the insertion
1076 point is at the end of the line, in which case the character
1077 behind the cursor is deleted. COUNT is obeyed and may be used
1078 to delete forward or backward that many characters. */
1079int
1080rl_rubout_or_delete (count, key)
1081 int count, key;
1082{
1083 if (rl_end != 0 && rl_point == rl_end)
1084 return (_rl_rubout_char (count, key));
1085 else
1086 return (rl_delete (count, key));
1087}
1088
1089/* Delete all spaces and tabs around point. */
1090int
1091rl_delete_horizontal_space (count, ignore)
1092 int count, ignore;
1093{
1094 int start = rl_point;
Value stored to 'start' during its initialization is never read
1095
1096 while (rl_point && whitespace (rl_line_buffer[rl_point - 1])(((rl_line_buffer[rl_point - 1]) == ' ') || ((rl_line_buffer[
rl_point - 1]) == '\t'))
)
1097 rl_point--;
1098
1099 start = rl_point;
1100
1101 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])(((rl_line_buffer[rl_point]) == ' ') || ((rl_line_buffer[rl_point
]) == '\t'))
)
1102 rl_point++;
1103
1104 if (start != rl_point)
1105 {
1106 rl_delete_text (start, rl_point);
1107 rl_point = start;
1108 }
1109 return 0;
1110}
1111
1112/* Like the tcsh editing function delete-char-or-list. The eof character
1113 is caught before this is invoked, so this really does the same thing as
1114 delete-char-or-list-or-eof, as long as it's bound to the eof character. */
1115int
1116rl_delete_or_show_completions (count, key)
1117 int count, key;
1118{
1119 if (rl_end != 0 && rl_point == rl_end)
1120 return (rl_possible_completions (count, key));
1121 else
1122 return (rl_delete (count, key));
1123}
1124
1125#ifndef RL_COMMENT_BEGIN_DEFAULT"#"
1126#define RL_COMMENT_BEGIN_DEFAULT"#" "#"
1127#endif
1128
1129/* Turn the current line into a comment in shell history.
1130 A K*rn shell style function. */
1131int
1132rl_insert_comment (count, key)
1133 int count, key;
1134{
1135 char *rl_comment_text;
1136 int rl_comment_len;
1137
1138 rl_beg_of_line (1, key);
1139 rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT"#";
1140
1141 if (rl_explicit_arg == 0)
1142 rl_insert_text (rl_comment_text);
1143 else
1144 {
1145 rl_comment_len = strlen (rl_comment_text);
1146 if (STREQN (rl_comment_text, rl_line_buffer, rl_comment_len)(((rl_comment_len) == 0) ? (1) : ((rl_comment_text)[0] == (rl_line_buffer
)[0]) && (strncmp ((rl_comment_text), (rl_line_buffer
), (rl_comment_len)) == 0))
)
1147 rl_delete_text (rl_point, rl_point + rl_comment_len);
1148 else
1149 rl_insert_text (rl_comment_text);
1150 }
1151
1152 (*rl_redisplay_function) ();
1153 rl_newline (1, '\n');
1154
1155 return (0);
1156}
1157
1158/* **************************************************************** */
1159/* */
1160/* Changing Case */
1161/* */
1162/* **************************************************************** */
1163
1164/* The three kinds of things that we know how to do. */
1165#define UpCase1 1
1166#define DownCase2 2
1167#define CapCase3 3
1168
1169/* Uppercase the word at point. */
1170int
1171rl_upcase_word (count, key)
1172 int count, key;
1173{
1174 return (rl_change_case (count, UpCase1));
1175}
1176
1177/* Lowercase the word at point. */
1178int
1179rl_downcase_word (count, key)
1180 int count, key;
1181{
1182 return (rl_change_case (count, DownCase2));
1183}
1184
1185/* Upcase the first letter, downcase the rest. */
1186int
1187rl_capitalize_word (count, key)
1188 int count, key;
1189{
1190 return (rl_change_case (count, CapCase3));
1191}
1192
1193/* The meaty function.
1194 Change the case of COUNT words, performing OP on them.
1195 OP is one of UpCase, DownCase, or CapCase.
1196 If a negative argument is given, leave point where it started,
1197 otherwise, leave it where it moves to. */
1198static int
1199rl_change_case (count, op)
1200 int count, op;
1201{
1202 register int start, end;
1203 int inword, c;
1204
1205 start = rl_point;
1206 rl_forward_word (count, 0);
1207 end = rl_point;
1208
1209 if (count < 0)
1210 SWAP (start, end)do { int t; t = start; start = end; end = t; } while (0);
1211
1212 /* We are going to modify some text, so let's prepare to undo it. */
1213 rl_modifying (start, end);
1214
1215 for (inword = 0; start < end; start++)
1216 {
1217 c = rl_line_buffer[start];
1218 switch (op)
1219 {
1220 case UpCase1:
1221 rl_line_buffer[start] = _rl_to_upper (c)((((unsigned char)(c) == (c)) && (isascii(c) &&
islower (c))) ? toupper((unsigned char)c) : (c))
;
1222 break;
1223
1224 case DownCase2:
1225 rl_line_buffer[start] = _rl_to_lower (c)((((unsigned char)(c) == (c)) && (isascii(c) &&
isupper (c))) ? tolower((unsigned char)c) : (c))
;
1226 break;
1227
1228 case CapCase3:
1229 rl_line_buffer[start] = (inword == 0) ? _rl_to_upper (c)((((unsigned char)(c) == (c)) && (isascii(c) &&
islower (c))) ? toupper((unsigned char)c) : (c))
: _rl_to_lower (c)((((unsigned char)(c) == (c)) && (isascii(c) &&
isupper (c))) ? tolower((unsigned char)c) : (c))
;
1230 inword = rl_alphabetic (rl_line_buffer[start]);
1231 break;
1232
1233 default:
1234 rl_ding ();
1235 return -1;
1236 }
1237 }
1238 rl_point = end;
1239 return 0;
1240}
1241
1242/* **************************************************************** */
1243/* */
1244/* Transposition */
1245/* */
1246/* **************************************************************** */
1247
1248/* Transpose the words at point. If point is at the end of the line,
1249 transpose the two words before point. */
1250int
1251rl_transpose_words (count, key)
1252 int count, key;
1253{
1254 char *word1, *word2;
1255 int w1_beg, w1_end, w2_beg, w2_end;
1256 int orig_point = rl_point;
1257
1258 if (!count)
1259 return 0;
1260
1261 /* Find the two words. */
1262 rl_forward_word (count, key);
1263 w2_end = rl_point;
1264 rl_backward_word (1, key);
1265 w2_beg = rl_point;
1266 rl_backward_word (count, key);
1267 w1_beg = rl_point;
1268 rl_forward_word (1, key);
1269 w1_end = rl_point;
1270
1271 /* Do some check to make sure that there really are two words. */
1272 if ((w1_beg == w2_beg) || (w2_beg < w1_end))
1273 {
1274 rl_ding ();
1275 rl_point = orig_point;
1276 return -1;
1277 }
1278
1279 /* Get the text of the words. */
1280 word1 = rl_copy_text (w1_beg, w1_end);
1281 word2 = rl_copy_text (w2_beg, w2_end);
1282
1283 /* We are about to do many insertions and deletions. Remember them
1284 as one operation. */
1285 rl_begin_undo_group ();
1286
1287 /* Do the stuff at word2 first, so that we don't have to worry
1288 about word1 moving. */
1289 rl_point = w2_beg;
1290 rl_delete_text (w2_beg, w2_end);
1291 rl_insert_text (word1);
1292
1293 rl_point = w1_beg;
1294 rl_delete_text (w1_beg, w1_end);
1295 rl_insert_text (word2);
1296
1297 /* This is exactly correct since the text before this point has not
1298 changed in length. */
1299 rl_point = w2_end;
1300
1301 /* I think that does it. */
1302 rl_end_undo_group ();
1303 free (word1);
1304 free (word2);
1305
1306 return 0;
1307}
1308
1309/* Transpose the characters at point. If point is at the end of the line,
1310 then transpose the characters before point. */
1311int
1312rl_transpose_chars (count, key)
1313 int count, key;
1314{
1315#if defined (HANDLE_MULTIBYTE)
1316 char *dummy;
1317 int i, prev_point;
1318#else
1319 char dummy[2];
1320#endif
1321 int char_length;
1322
1323 if (count == 0)
1324 return 0;
1325
1326 if (!rl_point || rl_end < 2)
1327 {
1328 rl_ding ();
1329 return -1;
1330 }
1331
1332 rl_begin_undo_group ();
1333
1334 if (rl_point == rl_end)
1335 {
1336 if (MB_CUR_MAX1 > 1 && rl_byte_oriented == 0)
1337 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO)(((rl_point) == 0) ? (rl_point) : ((rl_point) - 1));
1338 else
1339 --rl_point;
1340 count = 1;
1341 }
1342
1343#if defined (HANDLE_MULTIBYTE)
1344 prev_point = rl_point;
1345 if (MB_CUR_MAX1 > 1 && rl_byte_oriented == 0)
1346 rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO)(((rl_point) == 0) ? (rl_point) : ((rl_point) - 1));
1347 else
1348#endif
1349 rl_point--;
1350
1351#if defined (HANDLE_MULTIBYTE)
1352 char_length = prev_point - rl_point;
1353 dummy = (char *)xmalloc (char_length + 1);
1354 for (i = 0; i < char_length; i++)
1355 dummy[i] = rl_line_buffer[rl_point + i];
1356 dummy[i] = '\0';
1357#else
1358 dummy[0] = rl_line_buffer[rl_point];
1359 dummy[char_length = 1] = '\0';
1360#endif
1361
1362 rl_delete_text (rl_point, rl_point + char_length);
1363
1364 rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO)((rl_point) + (count));
1365
1366 _rl_fix_point (0);
1367 rl_insert_text (dummy);
1368 rl_end_undo_group ();
1369
1370#if defined (HANDLE_MULTIBYTE)
1371 free (dummy);
1372#endif
1373
1374 return 0;
1375}
1376
1377/* **************************************************************** */
1378/* */
1379/* Character Searching */
1380/* */
1381/* **************************************************************** */
1382
1383int
1384#if defined (HANDLE_MULTIBYTE)
1385_rl_char_search_internal (count, dir, smbchar, len)
1386 int count, dir;
1387 char *smbchar;
1388 int len;
1389#else
1390_rl_char_search_internal (count, dir, schar)
1391 int count, dir, schar;
1392#endif
1393{
1394 int pos, inc;
1395#if defined (HANDLE_MULTIBYTE)
1396 int prepos;
1397#endif
1398
1399 pos = rl_point;
1400 inc = (dir < 0) ? -1 : 1;
1401 while (count)
1402 {
1403 if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end))
1404 {
1405 rl_ding ();
1406 return -1;
1407 }
1408
1409#if defined (HANDLE_MULTIBYTE)
1410 pos = (inc > 0) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)((pos) + (1))
1411 : _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)(((pos) == 0) ? (pos) : ((pos) - 1));
1412#else
1413 pos += inc;
1414#endif
1415 do
1416 {
1417#if defined (HANDLE_MULTIBYTE)
1418 if (_rl_is_mbchar_matched (rl_line_buffer, pos, rl_end, smbchar, len))
1419#else
1420 if (rl_line_buffer[pos] == schar)
1421#endif
1422 {
1423 count--;
1424 if (dir < 0)
1425 rl_point = (dir == BTO-1) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)((pos) + (1))
1426 : pos;
1427 else
1428 rl_point = (dir == FTO1) ? _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)(((pos) == 0) ? (pos) : ((pos) - 1))
1429 : pos;
1430 break;
1431 }
1432#if defined (HANDLE_MULTIBYTE)
1433 prepos = pos;
1434#endif
1435 }
1436#if defined (HANDLE_MULTIBYTE)
1437 while ((dir < 0) ? (pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)(((pos) == 0) ? (pos) : ((pos) - 1))) != prepos
1438 : (pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)((pos) + (1))) != prepos);
1439#else
1440 while ((dir < 0) ? pos-- : ++pos < rl_end);
1441#endif
1442 }
1443 return (0);
1444}
1445
1446/* Search COUNT times for a character read from the current input stream.
1447 FDIR is the direction to search if COUNT is non-negative; otherwise
1448 the search goes in BDIR. So much is dependent on HANDLE_MULTIBYTE
1449 that there are two separate versions of this function. */
1450#if defined (HANDLE_MULTIBYTE)
1451static int
1452_rl_char_search (count, fdir, bdir)
1453 int count, fdir, bdir;
1454{
1455 char mbchar[MB_LEN_MAX1];
1456 int mb_len;
1457
1458 mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX1);
1459
1460 if (count < 0)
1461 return (_rl_char_search_internal (-count, bdir, mbchar, mb_len));
1462 else
1463 return (_rl_char_search_internal (count, fdir, mbchar, mb_len));
1464}
1465#else /* !HANDLE_MULTIBYTE */
1466static int
1467_rl_char_search (count, fdir, bdir)
1468 int count, fdir, bdir;
1469{
1470 int c;
1471
1472 RL_SETSTATE(RL_STATE_MOREINPUT)(rl_readline_state |= (0x00040));
1473 c = rl_read_key ();
1474 RL_UNSETSTATE(RL_STATE_MOREINPUT)(rl_readline_state &= ~(0x00040));
1475
1476 if (count < 0)
1477 return (_rl_char_search_internal (-count, bdir, c));
1478 else
1479 return (_rl_char_search_internal (count, fdir, c));
1480}
1481#endif /* !HANDLE_MULTIBYTE */
1482
1483int
1484rl_char_search (count, key)
1485 int count, key;
1486{
1487 return (_rl_char_search (count, FFIND2, BFIND-2));
1488}
1489
1490int
1491rl_backward_char_search (count, key)
1492 int count, key;
1493{
1494 return (_rl_char_search (count, BFIND-2, FFIND2));
1495}
1496
1497/* **************************************************************** */
1498/* */
1499/* The Mark and the Region. */
1500/* */
1501/* **************************************************************** */
1502
1503/* Set the mark at POSITION. */
1504int
1505_rl_set_mark_at_pos (position)
1506 int position;
1507{
1508 if (position > rl_end)
1509 return -1;
1510
1511 rl_mark = position;
1512 return 0;
1513}
1514
1515/* A bindable command to set the mark. */
1516int
1517rl_set_mark (count, key)
1518 int count, key;
1519{
1520 return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point));
1521}
1522
1523/* Exchange the position of mark and point. */
1524int
1525rl_exchange_point_and_mark (count, key)
1526 int count, key;
1527{
1528 if (rl_mark > rl_end)
1529 rl_mark = -1;
1530
1531 if (rl_mark == -1)
1532 {
1533 rl_ding ();
1534 return -1;
1535 }
1536 else
1537 SWAP (rl_point, rl_mark)do { int t; t = rl_point; rl_point = rl_mark; rl_mark = t; } while
(0)
;
1538
1539 return 0;
1540}