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_H)
25#  include <config.h>
26#endif
27
28#if defined (HAVE_UNISTD_H)
29#  include <unistd.h>
30#endif /* HAVE_UNISTD_H */
31
32#if defined (HAVE_STDLIB_H)
33#  include <stdlib.h>
34#else
35#  include "ansi_stdlib.h"
36#endif /* HAVE_STDLIB_H */
37
38#if defined (HAVE_LOCALE_H)
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));
63static int _rl_char_search PARAMS((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);
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);
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  strcpy (rl_line_buffer, text);
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_mode) : 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_MAX == 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);
292
293#if defined (VI_MODE)
294      if (rl_end <= point && rl_editing_mode == vi_mode)
295	point = _rl_find_prev_mbchar (rl_line_buffer, rl_end, MB_FIND_NONZERO);
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_MAX == 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);
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);
555  ch = rl_read_key ();
556  RL_UNSETSTATE(RL_STATE_MOREINPUT);
557
558  switch (_rl_to_upper (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_MAX > 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_MAX > 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_MAX];
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_MAX + 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_MAX == 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_MAX == 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_MAX];
797  int k;
798
799  /* Read an entire multibyte character sequence to insert COUNT times. */
800  if (count > 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
801    k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX);
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_MAX > 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_INSERT ? _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);
844  c = rl_read_key ();
845  RL_UNSETSTATE(RL_STATE_MOREINPUT);
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);
875
876#if defined (VI_MODE)
877  if (rl_editing_mode == vi_mode)
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_OVERWRITE)
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_MAX > 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_MAX == 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);
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_MAX == 1 || rl_byte_oriented)
1020#endif
1021      if (rl_point == rl_end && 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_MAX > 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_MAX > 1 && rl_byte_oriented == 0)
1067	new_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
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;
1095
1096  while (rl_point && whitespace (rl_line_buffer[rl_point - 1]))
1097    rl_point--;
1098
1099  start = rl_point;
1100
1101  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
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))
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 UpCase 1
1166#define DownCase 2
1167#define CapCase 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, UpCase));
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, DownCase));
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, CapCase));
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);
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 UpCase:
1221	  rl_line_buffer[start] = _rl_to_upper (c);
1222	  break;
1223
1224	case DownCase:
1225	  rl_line_buffer[start] = _rl_to_lower (c);
1226	  break;
1227
1228	case CapCase:
1229	  rl_line_buffer[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (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_MAX > 1 && rl_byte_oriented == 0)
1337	rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1338      else
1339	--rl_point;
1340      count = 1;
1341    }
1342
1343#if defined (HANDLE_MULTIBYTE)
1344  prev_point = rl_point;
1345  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1346    rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
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);
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)
1411		      : _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
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) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)
1426					: pos;
1427	      else
1428		rl_point = (dir == FTO) ? _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)
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)) != prepos
1438		       : (pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)) != 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_MAX];
1456  int mb_len;
1457
1458  mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX);
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);
1473  c = rl_read_key ();
1474  RL_UNSETSTATE(RL_STATE_MOREINPUT);
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, FFIND, BFIND));
1488}
1489
1490int
1491rl_backward_char_search (count, key)
1492     int count, key;
1493{
1494  return (_rl_char_search (count, BFIND, FFIND));
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);
1538
1539  return 0;
1540}
1541