1119610Sache/* text.c -- text handling commands for readline. */
2119610Sache
3157184Sache/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
4119610Sache
5119610Sache   This file is part of the GNU Readline Library, a library for
6119610Sache   reading lines of text with interactive input and history editing.
7119610Sache
8119610Sache   The GNU Readline Library is free software; you can redistribute it
9119610Sache   and/or modify it under the terms of the GNU General Public License
10119610Sache   as published by the Free Software Foundation; either version 2, or
11119610Sache   (at your option) any later version.
12119610Sache
13119610Sache   The GNU Readline Library is distributed in the hope that it will be
14119610Sache   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15119610Sache   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16119610Sache   GNU General Public License for more details.
17119610Sache
18119610Sache   The GNU General Public License is often shipped with GNU software, and
19119610Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
20119610Sache   have a copy of the license, write to the Free Software Foundation,
21119610Sache   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22119610Sache#define READLINE_LIBRARY
23119610Sache
24119610Sache#if defined (HAVE_CONFIG_H)
25119610Sache#  include <config.h>
26119610Sache#endif
27119610Sache
28119610Sache#if defined (HAVE_UNISTD_H)
29119610Sache#  include <unistd.h>
30119610Sache#endif /* HAVE_UNISTD_H */
31119610Sache
32119610Sache#if defined (HAVE_STDLIB_H)
33119610Sache#  include <stdlib.h>
34119610Sache#else
35119610Sache#  include "ansi_stdlib.h"
36119610Sache#endif /* HAVE_STDLIB_H */
37119610Sache
38119610Sache#if defined (HAVE_LOCALE_H)
39119610Sache#  include <locale.h>
40119610Sache#endif
41119610Sache
42119610Sache#include <stdio.h>
43119610Sache
44119610Sache/* System-specific feature definitions and include files. */
45119610Sache#include "rldefs.h"
46119610Sache#include "rlmbutil.h"
47119610Sache
48119610Sache#if defined (__EMX__)
49119610Sache#  define INCL_DOSPROCESS
50119610Sache#  include <os2.h>
51119610Sache#endif /* __EMX__ */
52119610Sache
53119610Sache/* Some standard library routines. */
54119610Sache#include "readline.h"
55119610Sache#include "history.h"
56119610Sache
57119610Sache#include "rlprivate.h"
58119610Sache#include "rlshell.h"
59119610Sache#include "xmalloc.h"
60119610Sache
61119610Sache/* Forward declarations. */
62119610Sachestatic int rl_change_case PARAMS((int, int));
63119610Sachestatic int _rl_char_search PARAMS((int, int, int));
64119610Sache
65157184Sache#if defined (READLINE_CALLBACKS)
66157184Sachestatic int _rl_insert_next_callback PARAMS((_rl_callback_generic_arg *));
67157184Sachestatic int _rl_char_search_callback PARAMS((_rl_callback_generic_arg *));
68157184Sache#endif
69157184Sache
70119610Sache/* **************************************************************** */
71119610Sache/*								    */
72119610Sache/*			Insert and Delete			    */
73119610Sache/*								    */
74119610Sache/* **************************************************************** */
75119610Sache
76119610Sache/* Insert a string of text into the line at point.  This is the only
77119610Sache   way that you should do insertion.  _rl_insert_char () calls this
78119610Sache   function.  Returns the number of characters inserted. */
79119610Sacheint
80119610Sacherl_insert_text (string)
81119610Sache     const char *string;
82119610Sache{
83119610Sache  register int i, l;
84119610Sache
85119610Sache  l = (string && *string) ? strlen (string) : 0;
86119610Sache  if (l == 0)
87119610Sache    return 0;
88119610Sache
89119610Sache  if (rl_end + l >= rl_line_buffer_len)
90119610Sache    rl_extend_line_buffer (rl_end + l);
91119610Sache
92119610Sache  for (i = rl_end; i >= rl_point; i--)
93119610Sache    rl_line_buffer[i + l] = rl_line_buffer[i];
94119610Sache  strncpy (rl_line_buffer + rl_point, string, l);
95119610Sache
96119610Sache  /* Remember how to undo this if we aren't undoing something. */
97119610Sache  if (_rl_doing_an_undo == 0)
98119610Sache    {
99119610Sache      /* If possible and desirable, concatenate the undos. */
100119610Sache      if ((l == 1) &&
101119610Sache	  rl_undo_list &&
102119610Sache	  (rl_undo_list->what == UNDO_INSERT) &&
103119610Sache	  (rl_undo_list->end == rl_point) &&
104119610Sache	  (rl_undo_list->end - rl_undo_list->start < 20))
105119610Sache	rl_undo_list->end++;
106119610Sache      else
107119610Sache	rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL);
108119610Sache    }
109119610Sache  rl_point += l;
110119610Sache  rl_end += l;
111119610Sache  rl_line_buffer[rl_end] = '\0';
112119610Sache  return l;
113119610Sache}
114119610Sache
115119610Sache/* Delete the string between FROM and TO.  FROM is inclusive, TO is not.
116119610Sache   Returns the number of characters deleted. */
117119610Sacheint
118119610Sacherl_delete_text (from, to)
119119610Sache     int from, to;
120119610Sache{
121119610Sache  register char *text;
122119610Sache  register int diff, i;
123119610Sache
124119610Sache  /* Fix it if the caller is confused. */
125119610Sache  if (from > to)
126119610Sache    SWAP (from, to);
127119610Sache
128119610Sache  /* fix boundaries */
129119610Sache  if (to > rl_end)
130119610Sache    {
131119610Sache      to = rl_end;
132119610Sache      if (from > to)
133119610Sache	from = to;
134119610Sache    }
135119610Sache  if (from < 0)
136119610Sache    from = 0;
137119610Sache
138119610Sache  text = rl_copy_text (from, to);
139119610Sache
140119610Sache  /* Some versions of strncpy() can't handle overlapping arguments. */
141119610Sache  diff = to - from;
142119610Sache  for (i = from; i < rl_end - diff; i++)
143119610Sache    rl_line_buffer[i] = rl_line_buffer[i + diff];
144119610Sache
145119610Sache  /* Remember how to undo this delete. */
146119610Sache  if (_rl_doing_an_undo == 0)
147119610Sache    rl_add_undo (UNDO_DELETE, from, to, text);
148119610Sache  else
149119610Sache    free (text);
150119610Sache
151119610Sache  rl_end -= diff;
152119610Sache  rl_line_buffer[rl_end] = '\0';
153119610Sache  return (diff);
154119610Sache}
155119610Sache
156119610Sache/* Fix up point so that it is within the line boundaries after killing
157119610Sache   text.  If FIX_MARK_TOO is non-zero, the mark is forced within line
158119610Sache   boundaries also. */
159119610Sache
160119610Sache#define _RL_FIX_POINT(x) \
161119610Sache	do { \
162119610Sache	if (x > rl_end) \
163119610Sache	  x = rl_end; \
164119610Sache	else if (x < 0) \
165119610Sache	  x = 0; \
166119610Sache	} while (0)
167119610Sache
168119610Sachevoid
169119610Sache_rl_fix_point (fix_mark_too)
170119610Sache     int fix_mark_too;
171119610Sache{
172119610Sache  _RL_FIX_POINT (rl_point);
173119610Sache  if (fix_mark_too)
174119610Sache    _RL_FIX_POINT (rl_mark);
175119610Sache}
176119610Sache#undef _RL_FIX_POINT
177119610Sache
178136644Sache/* Replace the contents of the line buffer between START and END with
179136644Sache   TEXT.  The operation is undoable.  To replace the entire line in an
180136644Sache   undoable mode, use _rl_replace_text(text, 0, rl_end); */
181119610Sacheint
182119610Sache_rl_replace_text (text, start, end)
183119610Sache     const char *text;
184119610Sache     int start, end;
185119610Sache{
186119610Sache  int n;
187119610Sache
188119610Sache  rl_begin_undo_group ();
189119610Sache  rl_delete_text (start, end + 1);
190119610Sache  rl_point = start;
191119610Sache  n = rl_insert_text (text);
192119610Sache  rl_end_undo_group ();
193119610Sache
194119610Sache  return n;
195119610Sache}
196119610Sache
197119610Sache/* Replace the current line buffer contents with TEXT.  If CLEAR_UNDO is
198119610Sache   non-zero, we free the current undo list. */
199119610Sachevoid
200119610Sacherl_replace_line (text, clear_undo)
201119610Sache     const char *text;
202119610Sache     int clear_undo;
203119610Sache{
204119610Sache  int len;
205119610Sache
206119610Sache  len = strlen (text);
207119610Sache  if (len >= rl_line_buffer_len)
208119610Sache    rl_extend_line_buffer (len);
209119610Sache  strcpy (rl_line_buffer, text);
210119610Sache  rl_end = len;
211119610Sache
212119610Sache  if (clear_undo)
213119610Sache    rl_free_undo_list ();
214119610Sache
215119610Sache  _rl_fix_point (1);
216119610Sache}
217119610Sache
218119610Sache/* **************************************************************** */
219119610Sache/*								    */
220119610Sache/*			Readline character functions		    */
221119610Sache/*								    */
222119610Sache/* **************************************************************** */
223119610Sache
224119610Sache/* This is not a gap editor, just a stupid line input routine.  No hair
225119610Sache   is involved in writing any of the functions, and none should be. */
226119610Sache
227119610Sache/* Note that:
228119610Sache
229119610Sache   rl_end is the place in the string that we would place '\0';
230119610Sache   i.e., it is always safe to place '\0' there.
231119610Sache
232119610Sache   rl_point is the place in the string where the cursor is.  Sometimes
233119610Sache   this is the same as rl_end.
234119610Sache
235119610Sache   Any command that is called interactively receives two arguments.
236119610Sache   The first is a count: the numeric arg pased to this command.
237119610Sache   The second is the key which invoked this command.
238119610Sache*/
239119610Sache
240119610Sache/* **************************************************************** */
241119610Sache/*								    */
242119610Sache/*			Movement Commands			    */
243119610Sache/*								    */
244119610Sache/* **************************************************************** */
245119610Sache
246119610Sache/* Note that if you `optimize' the display for these functions, you cannot
247119610Sache   use said functions in other functions which do not do optimizing display.
248119610Sache   I.e., you will have to update the data base for rl_redisplay, and you
249119610Sache   might as well let rl_redisplay do that job. */
250119610Sache
251119610Sache/* Move forward COUNT bytes. */
252119610Sacheint
253119610Sacherl_forward_byte (count, key)
254119610Sache     int count, key;
255119610Sache{
256119610Sache  if (count < 0)
257119610Sache    return (rl_backward_byte (-count, key));
258119610Sache
259119610Sache  if (count > 0)
260119610Sache    {
261119610Sache      int end = rl_point + count;
262119610Sache#if defined (VI_MODE)
263119610Sache      int lend = rl_end > 0 ? rl_end - (rl_editing_mode == vi_mode) : rl_end;
264119610Sache#else
265119610Sache      int lend = rl_end;
266119610Sache#endif
267119610Sache
268119610Sache      if (end > lend)
269119610Sache	{
270119610Sache	  rl_point = lend;
271119610Sache	  rl_ding ();
272119610Sache	}
273119610Sache      else
274119610Sache	rl_point = end;
275119610Sache    }
276119610Sache
277119610Sache  if (rl_end < 0)
278119610Sache    rl_end = 0;
279119610Sache
280119610Sache  return 0;
281119610Sache}
282119610Sache
283119610Sache#if defined (HANDLE_MULTIBYTE)
284119610Sache/* Move forward COUNT characters. */
285119610Sacheint
286119610Sacherl_forward_char (count, key)
287119610Sache     int count, key;
288119610Sache{
289119610Sache  int point;
290119610Sache
291119610Sache  if (MB_CUR_MAX == 1 || rl_byte_oriented)
292119610Sache    return (rl_forward_byte (count, key));
293119610Sache
294119610Sache  if (count < 0)
295119610Sache    return (rl_backward_char (-count, key));
296119610Sache
297119610Sache  if (count > 0)
298119610Sache    {
299119610Sache      point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
300119610Sache
301119610Sache#if defined (VI_MODE)
302119610Sache      if (rl_end <= point && rl_editing_mode == vi_mode)
303119610Sache	point = _rl_find_prev_mbchar (rl_line_buffer, rl_end, MB_FIND_NONZERO);
304119610Sache#endif
305119610Sache
306119610Sache      if (rl_point == point)
307119610Sache	rl_ding ();
308119610Sache
309119610Sache      rl_point = point;
310119610Sache
311119610Sache      if (rl_end < 0)
312119610Sache	rl_end = 0;
313119610Sache    }
314119610Sache
315119610Sache  return 0;
316119610Sache}
317119610Sache#else /* !HANDLE_MULTIBYTE */
318119610Sacheint
319119610Sacherl_forward_char (count, key)
320119610Sache     int count, key;
321119610Sache{
322119610Sache  return (rl_forward_byte (count, key));
323119610Sache}
324119610Sache#endif /* !HANDLE_MULTIBYTE */
325119610Sache
326119610Sache/* Backwards compatibility. */
327119610Sacheint
328119610Sacherl_forward (count, key)
329119610Sache     int count, key;
330119610Sache{
331119610Sache  return (rl_forward_char (count, key));
332119610Sache}
333119610Sache
334119610Sache/* Move backward COUNT bytes. */
335119610Sacheint
336119610Sacherl_backward_byte (count, key)
337119610Sache     int count, key;
338119610Sache{
339119610Sache  if (count < 0)
340119610Sache    return (rl_forward_byte (-count, key));
341119610Sache
342119610Sache  if (count > 0)
343119610Sache    {
344119610Sache      if (rl_point < count)
345119610Sache	{
346119610Sache	  rl_point = 0;
347119610Sache	  rl_ding ();
348119610Sache	}
349119610Sache      else
350119610Sache	rl_point -= count;
351119610Sache    }
352119610Sache
353119610Sache  if (rl_point < 0)
354119610Sache    rl_point = 0;
355119610Sache
356119610Sache  return 0;
357119610Sache}
358119610Sache
359119610Sache#if defined (HANDLE_MULTIBYTE)
360119610Sache/* Move backward COUNT characters. */
361119610Sacheint
362119610Sacherl_backward_char (count, key)
363119610Sache     int count, key;
364119610Sache{
365119610Sache  int point;
366119610Sache
367119610Sache  if (MB_CUR_MAX == 1 || rl_byte_oriented)
368119610Sache    return (rl_backward_byte (count, key));
369119610Sache
370119610Sache  if (count < 0)
371119610Sache    return (rl_forward_char (-count, key));
372119610Sache
373119610Sache  if (count > 0)
374119610Sache    {
375119610Sache      point = rl_point;
376119610Sache
377119610Sache      while (count > 0 && point > 0)
378119610Sache	{
379119610Sache	  point = _rl_find_prev_mbchar (rl_line_buffer, point, MB_FIND_NONZERO);
380119610Sache	  count--;
381119610Sache	}
382119610Sache      if (count > 0)
383119610Sache	{
384119610Sache	  rl_point = 0;
385119610Sache	  rl_ding ();
386119610Sache	}
387119610Sache      else
388119610Sache        rl_point = point;
389119610Sache    }
390119610Sache
391119610Sache  return 0;
392119610Sache}
393119610Sache#else
394119610Sacheint
395119610Sacherl_backward_char (count, key)
396119610Sache     int count, key;
397119610Sache{
398119610Sache  return (rl_backward_byte (count, key));
399119610Sache}
400119610Sache#endif
401119610Sache
402119610Sache/* Backwards compatibility. */
403119610Sacheint
404119610Sacherl_backward (count, key)
405119610Sache     int count, key;
406119610Sache{
407119610Sache  return (rl_backward_char (count, key));
408119610Sache}
409119610Sache
410119610Sache/* Move to the beginning of the line. */
411119610Sacheint
412119610Sacherl_beg_of_line (count, key)
413119610Sache     int count, key;
414119610Sache{
415119610Sache  rl_point = 0;
416119610Sache  return 0;
417119610Sache}
418119610Sache
419119610Sache/* Move to the end of the line. */
420119610Sacheint
421119610Sacherl_end_of_line (count, key)
422119610Sache     int count, key;
423119610Sache{
424119610Sache  rl_point = rl_end;
425119610Sache  return 0;
426119610Sache}
427119610Sache
428157184Sache/* Move forward a word.  We do what Emacs does.  Handles multibyte chars. */
429119610Sacheint
430119610Sacherl_forward_word (count, key)
431119610Sache     int count, key;
432119610Sache{
433119610Sache  int c;
434119610Sache
435119610Sache  if (count < 0)
436119610Sache    return (rl_backward_word (-count, key));
437119610Sache
438119610Sache  while (count)
439119610Sache    {
440119610Sache      if (rl_point == rl_end)
441119610Sache	return 0;
442119610Sache
443119610Sache      /* If we are not in a word, move forward until we are in one.
444119610Sache	 Then, move forward until we hit a non-alphabetic character. */
445157184Sache      c = _rl_char_value (rl_line_buffer, rl_point);
446157184Sache
447157184Sache      if (_rl_walphabetic (c) == 0)
448119610Sache	{
449157184Sache	  rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
450157184Sache	  while (rl_point < rl_end)
451119610Sache	    {
452157184Sache	      c = _rl_char_value (rl_line_buffer, rl_point);
453157184Sache	      if (_rl_walphabetic (c))
454119610Sache		break;
455157184Sache	      rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
456119610Sache	    }
457119610Sache	}
458119610Sache
459119610Sache      if (rl_point == rl_end)
460119610Sache	return 0;
461119610Sache
462157184Sache      rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
463157184Sache      while (rl_point < rl_end)
464119610Sache	{
465157184Sache	  c = _rl_char_value (rl_line_buffer, rl_point);
466157184Sache	  if (_rl_walphabetic (c) == 0)
467119610Sache	    break;
468157184Sache	  rl_point = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
469119610Sache	}
470157184Sache
471119610Sache      --count;
472119610Sache    }
473119610Sache
474119610Sache  return 0;
475119610Sache}
476119610Sache
477157184Sache/* Move backward a word.  We do what Emacs does.  Handles multibyte chars. */
478119610Sacheint
479119610Sacherl_backward_word (count, key)
480119610Sache     int count, key;
481119610Sache{
482157184Sache  int c, p;
483119610Sache
484119610Sache  if (count < 0)
485119610Sache    return (rl_forward_word (-count, key));
486119610Sache
487119610Sache  while (count)
488119610Sache    {
489157184Sache      if (rl_point == 0)
490119610Sache	return 0;
491119610Sache
492119610Sache      /* Like rl_forward_word (), except that we look at the characters
493119610Sache	 just before point. */
494119610Sache
495157184Sache      p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
496157184Sache      c = _rl_char_value (rl_line_buffer, p);
497157184Sache
498157184Sache      if (_rl_walphabetic (c) == 0)
499119610Sache	{
500157184Sache	  rl_point = p;
501157184Sache	  while (rl_point > 0)
502119610Sache	    {
503157184Sache	      p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
504157184Sache	      c = _rl_char_value (rl_line_buffer, p);
505157184Sache	      if (_rl_walphabetic (c))
506119610Sache		break;
507157184Sache	      rl_point = p;
508119610Sache	    }
509119610Sache	}
510119610Sache
511119610Sache      while (rl_point)
512119610Sache	{
513157184Sache	  p = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
514157184Sache	  c = _rl_char_value (rl_line_buffer, p);
515157184Sache	  if (_rl_walphabetic (c) == 0)
516119610Sache	    break;
517119610Sache	  else
518157184Sache	    rl_point = p;
519119610Sache	}
520119610Sache
521119610Sache      --count;
522119610Sache    }
523119610Sache
524119610Sache  return 0;
525119610Sache}
526119610Sache
527119610Sache/* Clear the current line.  Numeric argument to C-l does this. */
528119610Sacheint
529119610Sacherl_refresh_line (ignore1, ignore2)
530119610Sache     int ignore1, ignore2;
531119610Sache{
532119610Sache  int curr_line;
533119610Sache
534119610Sache  curr_line = _rl_current_display_line ();
535119610Sache
536119610Sache  _rl_move_vert (curr_line);
537119610Sache  _rl_move_cursor_relative (0, rl_line_buffer);   /* XXX is this right */
538119610Sache
539119610Sache  _rl_clear_to_eol (0);		/* arg of 0 means to not use spaces */
540119610Sache
541119610Sache  rl_forced_update_display ();
542119610Sache  rl_display_fixed = 1;
543119610Sache
544119610Sache  return 0;
545119610Sache}
546119610Sache
547119610Sache/* C-l typed to a line without quoting clears the screen, and then reprints
548119610Sache   the prompt and the current input line.  Given a numeric arg, redraw only
549119610Sache   the current line. */
550119610Sacheint
551119610Sacherl_clear_screen (count, key)
552119610Sache     int count, key;
553119610Sache{
554119610Sache  if (rl_explicit_arg)
555119610Sache    {
556119610Sache      rl_refresh_line (count, key);
557119610Sache      return 0;
558119610Sache    }
559119610Sache
560119610Sache  _rl_clear_screen ();		/* calls termcap function to clear screen */
561119610Sache  rl_forced_update_display ();
562119610Sache  rl_display_fixed = 1;
563119610Sache
564119610Sache  return 0;
565119610Sache}
566119610Sache
567119610Sacheint
568119610Sacherl_arrow_keys (count, c)
569119610Sache     int count, c;
570119610Sache{
571119610Sache  int ch;
572119610Sache
573119610Sache  RL_SETSTATE(RL_STATE_MOREINPUT);
574119610Sache  ch = rl_read_key ();
575119610Sache  RL_UNSETSTATE(RL_STATE_MOREINPUT);
576119610Sache
577119610Sache  switch (_rl_to_upper (ch))
578119610Sache    {
579119610Sache    case 'A':
580119610Sache      rl_get_previous_history (count, ch);
581119610Sache      break;
582119610Sache
583119610Sache    case 'B':
584119610Sache      rl_get_next_history (count, ch);
585119610Sache      break;
586119610Sache
587119610Sache    case 'C':
588119610Sache      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
589119610Sache	rl_forward_char (count, ch);
590119610Sache      else
591119610Sache	rl_forward_byte (count, ch);
592119610Sache      break;
593119610Sache
594119610Sache    case 'D':
595119610Sache      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
596119610Sache	rl_backward_char (count, ch);
597119610Sache      else
598119610Sache	rl_backward_byte (count, ch);
599119610Sache      break;
600119610Sache
601119610Sache    default:
602119610Sache      rl_ding ();
603119610Sache    }
604119610Sache
605119610Sache  return 0;
606119610Sache}
607119610Sache
608119610Sache/* **************************************************************** */
609119610Sache/*								    */
610119610Sache/*			Text commands				    */
611119610Sache/*								    */
612119610Sache/* **************************************************************** */
613119610Sache
614119610Sache#ifdef HANDLE_MULTIBYTE
615119610Sachestatic char pending_bytes[MB_LEN_MAX];
616119610Sachestatic int pending_bytes_length = 0;
617119610Sachestatic mbstate_t ps = {0};
618119610Sache#endif
619119610Sache
620119610Sache/* Insert the character C at the current location, moving point forward.
621119610Sache   If C introduces a multibyte sequence, we read the whole sequence and
622119610Sache   then insert the multibyte char into the line buffer. */
623119610Sacheint
624119610Sache_rl_insert_char (count, c)
625119610Sache     int count, c;
626119610Sache{
627119610Sache  register int i;
628119610Sache  char *string;
629119610Sache#ifdef HANDLE_MULTIBYTE
630119610Sache  int string_size;
631119610Sache  char incoming[MB_LEN_MAX + 1];
632119610Sache  int incoming_length = 0;
633119610Sache  mbstate_t ps_back;
634119610Sache  static int stored_count = 0;
635119610Sache#endif
636119610Sache
637119610Sache  if (count <= 0)
638119610Sache    return 0;
639119610Sache
640119610Sache#if defined (HANDLE_MULTIBYTE)
641119610Sache  if (MB_CUR_MAX == 1 || rl_byte_oriented)
642119610Sache    {
643119610Sache      incoming[0] = c;
644119610Sache      incoming[1] = '\0';
645119610Sache      incoming_length = 1;
646119610Sache    }
647119610Sache  else
648119610Sache    {
649119610Sache      wchar_t wc;
650119610Sache      size_t ret;
651119610Sache
652119610Sache      if (stored_count <= 0)
653119610Sache	stored_count = count;
654119610Sache      else
655119610Sache	count = stored_count;
656119610Sache
657119610Sache      ps_back = ps;
658119610Sache      pending_bytes[pending_bytes_length++] = c;
659119610Sache      ret = mbrtowc (&wc, pending_bytes, pending_bytes_length, &ps);
660119610Sache
661119610Sache      if (ret == (size_t)-2)
662119610Sache	{
663119610Sache	  /* Bytes too short to compose character, try to wait for next byte.
664119610Sache	     Restore the state of the byte sequence, because in this case the
665119610Sache	     effect of mbstate is undefined. */
666119610Sache	  ps = ps_back;
667119610Sache	  return 1;
668119610Sache	}
669119610Sache      else if (ret == (size_t)-1)
670119610Sache	{
671119610Sache	  /* Invalid byte sequence for the current locale.  Treat first byte
672119610Sache	     as a single character. */
673119610Sache	  incoming[0] = pending_bytes[0];
674119610Sache	  incoming[1] = '\0';
675119610Sache	  incoming_length = 1;
676119610Sache	  pending_bytes_length--;
677119610Sache	  memmove (pending_bytes, pending_bytes + 1, pending_bytes_length);
678119610Sache	  /* Clear the state of the byte sequence, because in this case the
679119610Sache	     effect of mbstate is undefined. */
680119610Sache	  memset (&ps, 0, sizeof (mbstate_t));
681119610Sache	}
682119610Sache      else if (ret == (size_t)0)
683119610Sache	{
684119610Sache	  incoming[0] = '\0';
685119610Sache	  incoming_length = 0;
686119610Sache	  pending_bytes_length--;
687119610Sache	  /* Clear the state of the byte sequence, because in this case the
688119610Sache	     effect of mbstate is undefined. */
689119610Sache	  memset (&ps, 0, sizeof (mbstate_t));
690119610Sache	}
691119610Sache      else
692119610Sache	{
693119610Sache	  /* We successfully read a single multibyte character. */
694119610Sache	  memcpy (incoming, pending_bytes, pending_bytes_length);
695119610Sache	  incoming[pending_bytes_length] = '\0';
696119610Sache	  incoming_length = pending_bytes_length;
697119610Sache	  pending_bytes_length = 0;
698119610Sache	}
699119610Sache    }
700119610Sache#endif /* HANDLE_MULTIBYTE */
701119610Sache
702119610Sache  /* If we can optimize, then do it.  But don't let people crash
703119610Sache     readline because of extra large arguments. */
704119610Sache  if (count > 1 && count <= 1024)
705119610Sache    {
706119610Sache#if defined (HANDLE_MULTIBYTE)
707119610Sache      string_size = count * incoming_length;
708119610Sache      string = (char *)xmalloc (1 + string_size);
709119610Sache
710119610Sache      i = 0;
711119610Sache      while (i < string_size)
712119610Sache	{
713119610Sache	  strncpy (string + i, incoming, incoming_length);
714119610Sache	  i += incoming_length;
715119610Sache	}
716119610Sache      incoming_length = 0;
717119610Sache      stored_count = 0;
718119610Sache#else /* !HANDLE_MULTIBYTE */
719119610Sache      string = (char *)xmalloc (1 + count);
720119610Sache
721119610Sache      for (i = 0; i < count; i++)
722119610Sache	string[i] = c;
723119610Sache#endif /* !HANDLE_MULTIBYTE */
724119610Sache
725119610Sache      string[i] = '\0';
726119610Sache      rl_insert_text (string);
727119610Sache      free (string);
728119610Sache
729119610Sache      return 0;
730119610Sache    }
731119610Sache
732119610Sache  if (count > 1024)
733119610Sache    {
734119610Sache      int decreaser;
735119610Sache#if defined (HANDLE_MULTIBYTE)
736119610Sache      string_size = incoming_length * 1024;
737119610Sache      string = (char *)xmalloc (1 + string_size);
738119610Sache
739119610Sache      i = 0;
740119610Sache      while (i < string_size)
741119610Sache	{
742119610Sache	  strncpy (string + i, incoming, incoming_length);
743119610Sache	  i += incoming_length;
744119610Sache	}
745119610Sache
746119610Sache      while (count)
747119610Sache	{
748119610Sache	  decreaser = (count > 1024) ? 1024 : count;
749119610Sache	  string[decreaser*incoming_length] = '\0';
750119610Sache	  rl_insert_text (string);
751119610Sache	  count -= decreaser;
752119610Sache	}
753119610Sache
754119610Sache      free (string);
755119610Sache      incoming_length = 0;
756119610Sache      stored_count = 0;
757119610Sache#else /* !HANDLE_MULTIBYTE */
758119610Sache      char str[1024+1];
759119610Sache
760119610Sache      for (i = 0; i < 1024; i++)
761119610Sache	str[i] = c;
762119610Sache
763119610Sache      while (count)
764119610Sache	{
765119610Sache	  decreaser = (count > 1024 ? 1024 : count);
766119610Sache	  str[decreaser] = '\0';
767119610Sache	  rl_insert_text (str);
768119610Sache	  count -= decreaser;
769119610Sache	}
770119610Sache#endif /* !HANDLE_MULTIBYTE */
771119610Sache
772119610Sache      return 0;
773119610Sache    }
774119610Sache
775119610Sache  if (MB_CUR_MAX == 1 || rl_byte_oriented)
776119610Sache    {
777119610Sache      /* We are inserting a single character.
778119610Sache	 If there is pending input, then make a string of all of the
779119610Sache	 pending characters that are bound to rl_insert, and insert
780119610Sache	 them all. */
781119610Sache      if (_rl_any_typein ())
782119610Sache	_rl_insert_typein (c);
783119610Sache      else
784119610Sache	{
785119610Sache	  /* Inserting a single character. */
786119610Sache	  char str[2];
787119610Sache
788119610Sache	  str[1] = '\0';
789119610Sache	  str[0] = c;
790119610Sache	  rl_insert_text (str);
791119610Sache	}
792157184Sache    }
793119610Sache#if defined (HANDLE_MULTIBYTE)
794119610Sache  else
795119610Sache    {
796119610Sache      rl_insert_text (incoming);
797119610Sache      stored_count = 0;
798119610Sache    }
799119610Sache#endif
800119610Sache
801119610Sache  return 0;
802119610Sache}
803119610Sache
804119610Sache/* Overwrite the character at point (or next COUNT characters) with C.
805119610Sache   If C introduces a multibyte character sequence, read the entire sequence
806119610Sache   before starting the overwrite loop. */
807119610Sacheint
808119610Sache_rl_overwrite_char (count, c)
809119610Sache     int count, c;
810119610Sache{
811119610Sache  int i;
812119610Sache#if defined (HANDLE_MULTIBYTE)
813119610Sache  char mbkey[MB_LEN_MAX];
814119610Sache  int k;
815119610Sache
816119610Sache  /* Read an entire multibyte character sequence to insert COUNT times. */
817119610Sache  if (count > 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
818119610Sache    k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX);
819119610Sache#endif
820119610Sache
821136644Sache  rl_begin_undo_group ();
822136644Sache
823119610Sache  for (i = 0; i < count; i++)
824119610Sache    {
825119610Sache#if defined (HANDLE_MULTIBYTE)
826119610Sache      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
827119610Sache	rl_insert_text (mbkey);
828119610Sache      else
829119610Sache#endif
830119610Sache	_rl_insert_char (1, c);
831119610Sache
832136644Sache      if (rl_point < rl_end)
833136644Sache	rl_delete (1, c);
834119610Sache    }
835119610Sache
836136644Sache  rl_end_undo_group ();
837136644Sache
838119610Sache  return 0;
839119610Sache}
840119610Sache
841119610Sacheint
842119610Sacherl_insert (count, c)
843119610Sache     int count, c;
844119610Sache{
845119610Sache  return (rl_insert_mode == RL_IM_INSERT ? _rl_insert_char (count, c)
846119610Sache  					 : _rl_overwrite_char (count, c));
847119610Sache}
848119610Sache
849119610Sache/* Insert the next typed character verbatim. */
850157184Sachestatic int
851157184Sache_rl_insert_next (count)
852157184Sache     int count;
853119610Sache{
854119610Sache  int c;
855119610Sache
856119610Sache  RL_SETSTATE(RL_STATE_MOREINPUT);
857119610Sache  c = rl_read_key ();
858119610Sache  RL_UNSETSTATE(RL_STATE_MOREINPUT);
859119610Sache
860173403Sache  if (c < 0)
861173403Sache    return -1;
862173403Sache
863119610Sache#if defined (HANDLE_SIGNALS)
864157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK) == 0)
865157184Sache    _rl_restore_tty_signals ();
866119610Sache#endif
867119610Sache
868119610Sache  return (_rl_insert_char (count, c));
869119610Sache}
870119610Sache
871157184Sache#if defined (READLINE_CALLBACKS)
872157184Sachestatic int
873157184Sache_rl_insert_next_callback (data)
874157184Sache     _rl_callback_generic_arg *data;
875157184Sache{
876157184Sache  int count;
877157184Sache
878157184Sache  count = data->count;
879157184Sache
880157184Sache  /* Deregister function, let rl_callback_read_char deallocate data */
881157184Sache  _rl_callback_func = 0;
882157184Sache  _rl_want_redisplay = 1;
883157184Sache
884157184Sache  return _rl_insert_next (count);
885157184Sache}
886157184Sache#endif
887157184Sache
888157184Sacheint
889157184Sacherl_quoted_insert (count, key)
890157184Sache     int count, key;
891157184Sache{
892157184Sache  /* Let's see...should the callback interface futz with signal handling? */
893157184Sache#if defined (HANDLE_SIGNALS)
894157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK) == 0)
895157184Sache    _rl_disable_tty_signals ();
896157184Sache#endif
897157184Sache
898157184Sache#if defined (READLINE_CALLBACKS)
899157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK))
900157184Sache    {
901157184Sache      _rl_callback_data = _rl_callback_data_alloc (count);
902157184Sache      _rl_callback_func = _rl_insert_next_callback;
903157184Sache      return (0);
904157184Sache    }
905157184Sache#endif
906157184Sache
907157184Sache  return _rl_insert_next (count);
908157184Sache}
909157184Sache
910119610Sache/* Insert a tab character. */
911119610Sacheint
912119610Sacherl_tab_insert (count, key)
913119610Sache     int count, key;
914119610Sache{
915119610Sache  return (_rl_insert_char (count, '\t'));
916119610Sache}
917119610Sache
918119610Sache/* What to do when a NEWLINE is pressed.  We accept the whole line.
919119610Sache   KEY is the key that invoked this command.  I guess it could have
920119610Sache   meaning in the future. */
921119610Sacheint
922119610Sacherl_newline (count, key)
923119610Sache     int count, key;
924119610Sache{
925119610Sache  rl_done = 1;
926119610Sache
927119610Sache  if (_rl_history_preserve_point)
928119610Sache    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
929119610Sache
930119610Sache  RL_SETSTATE(RL_STATE_DONE);
931119610Sache
932119610Sache#if defined (VI_MODE)
933119610Sache  if (rl_editing_mode == vi_mode)
934119610Sache    {
935119610Sache      _rl_vi_done_inserting ();
936136644Sache      if (_rl_vi_textmod_command (_rl_vi_last_command) == 0)	/* XXX */
937136644Sache	_rl_vi_reset_last ();
938119610Sache    }
939119610Sache#endif /* VI_MODE */
940119610Sache
941119610Sache  /* If we've been asked to erase empty lines, suppress the final update,
942119610Sache     since _rl_update_final calls rl_crlf(). */
943119610Sache  if (rl_erase_empty_line && rl_point == 0 && rl_end == 0)
944119610Sache    return 0;
945119610Sache
946119610Sache  if (readline_echoing_p)
947119610Sache    _rl_update_final ();
948119610Sache  return 0;
949119610Sache}
950119610Sache
951119610Sache/* What to do for some uppercase characters, like meta characters,
952119610Sache   and some characters appearing in emacs_ctlx_keymap.  This function
953119610Sache   is just a stub, you bind keys to it and the code in _rl_dispatch ()
954119610Sache   is special cased. */
955119610Sacheint
956119610Sacherl_do_lowercase_version (ignore1, ignore2)
957119610Sache     int ignore1, ignore2;
958119610Sache{
959119610Sache  return 0;
960119610Sache}
961119610Sache
962119610Sache/* This is different from what vi does, so the code's not shared.  Emacs
963119610Sache   rubout in overwrite mode has one oddity:  it replaces a control
964119610Sache   character that's displayed as two characters (^X) with two spaces. */
965119610Sacheint
966119610Sache_rl_overwrite_rubout (count, key)
967119610Sache     int count, key;
968119610Sache{
969119610Sache  int opoint;
970119610Sache  int i, l;
971119610Sache
972119610Sache  if (rl_point == 0)
973119610Sache    {
974119610Sache      rl_ding ();
975119610Sache      return 1;
976119610Sache    }
977119610Sache
978119610Sache  opoint = rl_point;
979119610Sache
980119610Sache  /* L == number of spaces to insert */
981119610Sache  for (i = l = 0; i < count; i++)
982119610Sache    {
983119610Sache      rl_backward_char (1, key);
984119610Sache      l += rl_character_len (rl_line_buffer[rl_point], rl_point);	/* not exactly right */
985119610Sache    }
986119610Sache
987119610Sache  rl_begin_undo_group ();
988119610Sache
989119610Sache  if (count > 1 || rl_explicit_arg)
990119610Sache    rl_kill_text (opoint, rl_point);
991119610Sache  else
992119610Sache    rl_delete_text (opoint, rl_point);
993119610Sache
994119610Sache  /* Emacs puts point at the beginning of the sequence of spaces. */
995136644Sache  if (rl_point < rl_end)
996136644Sache    {
997136644Sache      opoint = rl_point;
998136644Sache      _rl_insert_char (l, ' ');
999136644Sache      rl_point = opoint;
1000136644Sache    }
1001119610Sache
1002119610Sache  rl_end_undo_group ();
1003119610Sache
1004119610Sache  return 0;
1005119610Sache}
1006119610Sache
1007119610Sache/* Rubout the character behind point. */
1008119610Sacheint
1009119610Sacherl_rubout (count, key)
1010119610Sache     int count, key;
1011119610Sache{
1012119610Sache  if (count < 0)
1013119610Sache    return (rl_delete (-count, key));
1014119610Sache
1015119610Sache  if (!rl_point)
1016119610Sache    {
1017119610Sache      rl_ding ();
1018119610Sache      return -1;
1019119610Sache    }
1020119610Sache
1021119610Sache  if (rl_insert_mode == RL_IM_OVERWRITE)
1022119610Sache    return (_rl_overwrite_rubout (count, key));
1023119610Sache
1024119610Sache  return (_rl_rubout_char (count, key));
1025119610Sache}
1026119610Sache
1027119610Sacheint
1028119610Sache_rl_rubout_char (count, key)
1029119610Sache     int count, key;
1030119610Sache{
1031119610Sache  int orig_point;
1032119610Sache  unsigned char c;
1033119610Sache
1034119610Sache  /* Duplicated code because this is called from other parts of the library. */
1035119610Sache  if (count < 0)
1036119610Sache    return (rl_delete (-count, key));
1037119610Sache
1038119610Sache  if (rl_point == 0)
1039119610Sache    {
1040119610Sache      rl_ding ();
1041119610Sache      return -1;
1042119610Sache    }
1043119610Sache
1044157184Sache  orig_point = rl_point;
1045119610Sache  if (count > 1 || rl_explicit_arg)
1046119610Sache    {
1047157184Sache      rl_backward_char (count, key);
1048119610Sache      rl_kill_text (orig_point, rl_point);
1049119610Sache    }
1050157184Sache  else if (MB_CUR_MAX == 1 || rl_byte_oriented)
1051119610Sache    {
1052157184Sache      c = rl_line_buffer[--rl_point];
1053157184Sache      rl_delete_text (rl_point, orig_point);
1054157184Sache      /* The erase-at-end-of-line hack is of questionable merit now. */
1055119610Sache      if (rl_point == rl_end && ISPRINT (c) && _rl_last_c_pos)
1056119610Sache	{
1057119610Sache	  int l;
1058119610Sache	  l = rl_character_len (c, rl_point);
1059119610Sache	  _rl_erase_at_end_of_line (l);
1060119610Sache	}
1061119610Sache    }
1062157184Sache  else
1063157184Sache    {
1064157184Sache      rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1065157184Sache      rl_delete_text (rl_point, orig_point);
1066157184Sache    }
1067119610Sache
1068119610Sache  return 0;
1069119610Sache}
1070119610Sache
1071119610Sache/* Delete the character under the cursor.  Given a numeric argument,
1072119610Sache   kill that many characters instead. */
1073119610Sacheint
1074119610Sacherl_delete (count, key)
1075119610Sache     int count, key;
1076119610Sache{
1077165670Sache  int xpoint;
1078165670Sache
1079119610Sache  if (count < 0)
1080119610Sache    return (_rl_rubout_char (-count, key));
1081119610Sache
1082119610Sache  if (rl_point == rl_end)
1083119610Sache    {
1084119610Sache      rl_ding ();
1085119610Sache      return -1;
1086119610Sache    }
1087119610Sache
1088119610Sache  if (count > 1 || rl_explicit_arg)
1089119610Sache    {
1090165670Sache      xpoint = rl_point;
1091119610Sache      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1092119610Sache	rl_forward_char (count, key);
1093119610Sache      else
1094119610Sache	rl_forward_byte (count, key);
1095119610Sache
1096165670Sache      rl_kill_text (xpoint, rl_point);
1097165670Sache      rl_point = xpoint;
1098119610Sache    }
1099119610Sache  else
1100119610Sache    {
1101165670Sache      xpoint = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
1102165670Sache      rl_delete_text (rl_point, xpoint);
1103119610Sache    }
1104157191Sache  return 0;
1105119610Sache}
1106119610Sache
1107119610Sache/* Delete the character under the cursor, unless the insertion
1108119610Sache   point is at the end of the line, in which case the character
1109119610Sache   behind the cursor is deleted.  COUNT is obeyed and may be used
1110119610Sache   to delete forward or backward that many characters. */
1111119610Sacheint
1112119610Sacherl_rubout_or_delete (count, key)
1113119610Sache     int count, key;
1114119610Sache{
1115119610Sache  if (rl_end != 0 && rl_point == rl_end)
1116119610Sache    return (_rl_rubout_char (count, key));
1117119610Sache  else
1118119610Sache    return (rl_delete (count, key));
1119119610Sache}
1120119610Sache
1121119610Sache/* Delete all spaces and tabs around point. */
1122119610Sacheint
1123119610Sacherl_delete_horizontal_space (count, ignore)
1124119610Sache     int count, ignore;
1125119610Sache{
1126119610Sache  int start = rl_point;
1127119610Sache
1128119610Sache  while (rl_point && whitespace (rl_line_buffer[rl_point - 1]))
1129119610Sache    rl_point--;
1130119610Sache
1131119610Sache  start = rl_point;
1132119610Sache
1133119610Sache  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1134119610Sache    rl_point++;
1135119610Sache
1136119610Sache  if (start != rl_point)
1137119610Sache    {
1138119610Sache      rl_delete_text (start, rl_point);
1139119610Sache      rl_point = start;
1140119610Sache    }
1141157184Sache
1142157184Sache  if (rl_point < 0)
1143157184Sache    rl_point = 0;
1144157184Sache
1145119610Sache  return 0;
1146119610Sache}
1147119610Sache
1148119610Sache/* Like the tcsh editing function delete-char-or-list.  The eof character
1149119610Sache   is caught before this is invoked, so this really does the same thing as
1150119610Sache   delete-char-or-list-or-eof, as long as it's bound to the eof character. */
1151119610Sacheint
1152119610Sacherl_delete_or_show_completions (count, key)
1153119610Sache     int count, key;
1154119610Sache{
1155119610Sache  if (rl_end != 0 && rl_point == rl_end)
1156119610Sache    return (rl_possible_completions (count, key));
1157119610Sache  else
1158119610Sache    return (rl_delete (count, key));
1159119610Sache}
1160119610Sache
1161119610Sache#ifndef RL_COMMENT_BEGIN_DEFAULT
1162119610Sache#define RL_COMMENT_BEGIN_DEFAULT "#"
1163119610Sache#endif
1164119610Sache
1165119610Sache/* Turn the current line into a comment in shell history.
1166119610Sache   A K*rn shell style function. */
1167119610Sacheint
1168119610Sacherl_insert_comment (count, key)
1169119610Sache     int count, key;
1170119610Sache{
1171119610Sache  char *rl_comment_text;
1172119610Sache  int rl_comment_len;
1173119610Sache
1174119610Sache  rl_beg_of_line (1, key);
1175119610Sache  rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT;
1176119610Sache
1177119610Sache  if (rl_explicit_arg == 0)
1178119610Sache    rl_insert_text (rl_comment_text);
1179119610Sache  else
1180119610Sache    {
1181119610Sache      rl_comment_len = strlen (rl_comment_text);
1182119610Sache      if (STREQN (rl_comment_text, rl_line_buffer, rl_comment_len))
1183119610Sache	rl_delete_text (rl_point, rl_point + rl_comment_len);
1184119610Sache      else
1185119610Sache	rl_insert_text (rl_comment_text);
1186119610Sache    }
1187119610Sache
1188119610Sache  (*rl_redisplay_function) ();
1189119610Sache  rl_newline (1, '\n');
1190119610Sache
1191119610Sache  return (0);
1192119610Sache}
1193119610Sache
1194119610Sache/* **************************************************************** */
1195119610Sache/*								    */
1196119610Sache/*			Changing Case				    */
1197119610Sache/*								    */
1198119610Sache/* **************************************************************** */
1199119610Sache
1200119610Sache/* The three kinds of things that we know how to do. */
1201119610Sache#define UpCase 1
1202119610Sache#define DownCase 2
1203119610Sache#define CapCase 3
1204119610Sache
1205119610Sache/* Uppercase the word at point. */
1206119610Sacheint
1207119610Sacherl_upcase_word (count, key)
1208119610Sache     int count, key;
1209119610Sache{
1210119610Sache  return (rl_change_case (count, UpCase));
1211119610Sache}
1212119610Sache
1213119610Sache/* Lowercase the word at point. */
1214119610Sacheint
1215119610Sacherl_downcase_word (count, key)
1216119610Sache     int count, key;
1217119610Sache{
1218119610Sache  return (rl_change_case (count, DownCase));
1219119610Sache}
1220119610Sache
1221119610Sache/* Upcase the first letter, downcase the rest. */
1222119610Sacheint
1223119610Sacherl_capitalize_word (count, key)
1224119610Sache     int count, key;
1225119610Sache{
1226119610Sache return (rl_change_case (count, CapCase));
1227119610Sache}
1228119610Sache
1229119610Sache/* The meaty function.
1230119610Sache   Change the case of COUNT words, performing OP on them.
1231119610Sache   OP is one of UpCase, DownCase, or CapCase.
1232119610Sache   If a negative argument is given, leave point where it started,
1233119610Sache   otherwise, leave it where it moves to. */
1234119610Sachestatic int
1235119610Sacherl_change_case (count, op)
1236119610Sache     int count, op;
1237119610Sache{
1238157184Sache  int start, next, end;
1239157184Sache  int inword, c, nc, nop;
1240157184Sache#if defined (HANDLE_MULTIBYTE)
1241157184Sache  wchar_t wc, nwc;
1242157184Sache  char mb[MB_LEN_MAX+1];
1243165670Sache  int mlen;
1244165670Sache  mbstate_t mps;
1245157184Sache#endif
1246119610Sache
1247119610Sache  start = rl_point;
1248119610Sache  rl_forward_word (count, 0);
1249119610Sache  end = rl_point;
1250119610Sache
1251157184Sache  if (op != UpCase && op != DownCase && op != CapCase)
1252157184Sache    {
1253157184Sache      rl_ding ();
1254157184Sache      return -1;
1255157184Sache    }
1256157184Sache
1257119610Sache  if (count < 0)
1258119610Sache    SWAP (start, end);
1259119610Sache
1260157184Sache#if defined (HANDLE_MULTIBYTE)
1261165670Sache  memset (&mps, 0, sizeof (mbstate_t));
1262157184Sache#endif
1263157184Sache
1264119610Sache  /* We are going to modify some text, so let's prepare to undo it. */
1265119610Sache  rl_modifying (start, end);
1266119610Sache
1267157184Sache  inword = 0;
1268157184Sache  while (start < end)
1269119610Sache    {
1270157184Sache      c = _rl_char_value (rl_line_buffer, start);
1271157184Sache      /*  This assumes that the upper and lower case versions are the same width. */
1272157184Sache      next = MB_NEXTCHAR (rl_line_buffer, start, 1, MB_FIND_NONZERO);
1273157184Sache
1274157184Sache      if (_rl_walphabetic (c) == 0)
1275119610Sache	{
1276157184Sache	  inword = 0;
1277157184Sache	  start = next;
1278157184Sache	  continue;
1279157184Sache	}
1280119610Sache
1281157184Sache      if (op == CapCase)
1282157184Sache	{
1283157184Sache	  nop = inword ? DownCase : UpCase;
1284157184Sache	  inword = 1;
1285157184Sache	}
1286157184Sache      else
1287157184Sache	nop = op;
1288157184Sache      if (MB_CUR_MAX == 1 || rl_byte_oriented || isascii (c))
1289157184Sache	{
1290157184Sache	  nc = (nop == UpCase) ? _rl_to_upper (c) : _rl_to_lower (c);
1291157184Sache	  rl_line_buffer[start] = nc;
1292157184Sache	}
1293157184Sache#if defined (HANDLE_MULTIBYTE)
1294157184Sache      else
1295157184Sache	{
1296165670Sache	  mbrtowc (&wc, rl_line_buffer + start, end - start, &mps);
1297157184Sache	  nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc);
1298157184Sache	  if  (nwc != wc)	/*  just skip unchanged characters */
1299157184Sache	    {
1300165670Sache	      mlen = wcrtomb (mb, nwc, &mps);
1301165670Sache	      if (mlen > 0)
1302165670Sache		mb[mlen] = '\0';
1303157184Sache	      /* Assume the same width */
1304165670Sache	      strncpy (rl_line_buffer + start, mb, mlen);
1305157184Sache	    }
1306157184Sache	}
1307157184Sache#endif
1308119610Sache
1309157184Sache      start = next;
1310157184Sache    }
1311119610Sache
1312119610Sache  rl_point = end;
1313119610Sache  return 0;
1314119610Sache}
1315119610Sache
1316119610Sache/* **************************************************************** */
1317119610Sache/*								    */
1318119610Sache/*			Transposition				    */
1319119610Sache/*								    */
1320119610Sache/* **************************************************************** */
1321119610Sache
1322119610Sache/* Transpose the words at point.  If point is at the end of the line,
1323119610Sache   transpose the two words before point. */
1324119610Sacheint
1325119610Sacherl_transpose_words (count, key)
1326119610Sache     int count, key;
1327119610Sache{
1328119610Sache  char *word1, *word2;
1329119610Sache  int w1_beg, w1_end, w2_beg, w2_end;
1330119610Sache  int orig_point = rl_point;
1331119610Sache
1332119610Sache  if (!count)
1333119610Sache    return 0;
1334119610Sache
1335119610Sache  /* Find the two words. */
1336119610Sache  rl_forward_word (count, key);
1337119610Sache  w2_end = rl_point;
1338119610Sache  rl_backward_word (1, key);
1339119610Sache  w2_beg = rl_point;
1340119610Sache  rl_backward_word (count, key);
1341119610Sache  w1_beg = rl_point;
1342119610Sache  rl_forward_word (1, key);
1343119610Sache  w1_end = rl_point;
1344119610Sache
1345119610Sache  /* Do some check to make sure that there really are two words. */
1346119610Sache  if ((w1_beg == w2_beg) || (w2_beg < w1_end))
1347119610Sache    {
1348119610Sache      rl_ding ();
1349119610Sache      rl_point = orig_point;
1350119610Sache      return -1;
1351119610Sache    }
1352119610Sache
1353119610Sache  /* Get the text of the words. */
1354119610Sache  word1 = rl_copy_text (w1_beg, w1_end);
1355119610Sache  word2 = rl_copy_text (w2_beg, w2_end);
1356119610Sache
1357119610Sache  /* We are about to do many insertions and deletions.  Remember them
1358119610Sache     as one operation. */
1359119610Sache  rl_begin_undo_group ();
1360119610Sache
1361119610Sache  /* Do the stuff at word2 first, so that we don't have to worry
1362119610Sache     about word1 moving. */
1363119610Sache  rl_point = w2_beg;
1364119610Sache  rl_delete_text (w2_beg, w2_end);
1365119610Sache  rl_insert_text (word1);
1366119610Sache
1367119610Sache  rl_point = w1_beg;
1368119610Sache  rl_delete_text (w1_beg, w1_end);
1369119610Sache  rl_insert_text (word2);
1370119610Sache
1371119610Sache  /* This is exactly correct since the text before this point has not
1372119610Sache     changed in length. */
1373119610Sache  rl_point = w2_end;
1374119610Sache
1375119610Sache  /* I think that does it. */
1376119610Sache  rl_end_undo_group ();
1377119610Sache  free (word1);
1378119610Sache  free (word2);
1379119610Sache
1380119610Sache  return 0;
1381119610Sache}
1382119610Sache
1383119610Sache/* Transpose the characters at point.  If point is at the end of the line,
1384119610Sache   then transpose the characters before point. */
1385119610Sacheint
1386119610Sacherl_transpose_chars (count, key)
1387119610Sache     int count, key;
1388119610Sache{
1389119610Sache#if defined (HANDLE_MULTIBYTE)
1390119610Sache  char *dummy;
1391157184Sache  int i;
1392119610Sache#else
1393119610Sache  char dummy[2];
1394119610Sache#endif
1395157184Sache  int char_length, prev_point;
1396119610Sache
1397119610Sache  if (count == 0)
1398119610Sache    return 0;
1399119610Sache
1400119610Sache  if (!rl_point || rl_end < 2)
1401119610Sache    {
1402119610Sache      rl_ding ();
1403119610Sache      return -1;
1404119610Sache    }
1405119610Sache
1406119610Sache  rl_begin_undo_group ();
1407119610Sache
1408119610Sache  if (rl_point == rl_end)
1409119610Sache    {
1410157184Sache      rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1411119610Sache      count = 1;
1412119610Sache    }
1413119610Sache
1414119610Sache  prev_point = rl_point;
1415157184Sache  rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1416119610Sache
1417119610Sache#if defined (HANDLE_MULTIBYTE)
1418119610Sache  char_length = prev_point - rl_point;
1419119610Sache  dummy = (char *)xmalloc (char_length + 1);
1420119610Sache  for (i = 0; i < char_length; i++)
1421119610Sache    dummy[i] = rl_line_buffer[rl_point + i];
1422119610Sache  dummy[i] = '\0';
1423119610Sache#else
1424119610Sache  dummy[0] = rl_line_buffer[rl_point];
1425119610Sache  dummy[char_length = 1] = '\0';
1426119610Sache#endif
1427119610Sache
1428119610Sache  rl_delete_text (rl_point, rl_point + char_length);
1429119610Sache
1430119610Sache  rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1431119610Sache
1432119610Sache  _rl_fix_point (0);
1433119610Sache  rl_insert_text (dummy);
1434119610Sache  rl_end_undo_group ();
1435119610Sache
1436119610Sache#if defined (HANDLE_MULTIBYTE)
1437119610Sache  free (dummy);
1438119610Sache#endif
1439119610Sache
1440119610Sache  return 0;
1441119610Sache}
1442119610Sache
1443119610Sache/* **************************************************************** */
1444119610Sache/*								    */
1445119610Sache/*			Character Searching			    */
1446119610Sache/*								    */
1447119610Sache/* **************************************************************** */
1448119610Sache
1449119610Sacheint
1450119610Sache#if defined (HANDLE_MULTIBYTE)
1451119610Sache_rl_char_search_internal (count, dir, smbchar, len)
1452119610Sache     int count, dir;
1453119610Sache     char *smbchar;
1454119610Sache     int len;
1455119610Sache#else
1456119610Sache_rl_char_search_internal (count, dir, schar)
1457119610Sache     int count, dir, schar;
1458119610Sache#endif
1459119610Sache{
1460119610Sache  int pos, inc;
1461119610Sache#if defined (HANDLE_MULTIBYTE)
1462119610Sache  int prepos;
1463119610Sache#endif
1464119610Sache
1465119610Sache  pos = rl_point;
1466119610Sache  inc = (dir < 0) ? -1 : 1;
1467119610Sache  while (count)
1468119610Sache    {
1469119610Sache      if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end))
1470119610Sache	{
1471119610Sache	  rl_ding ();
1472119610Sache	  return -1;
1473119610Sache	}
1474119610Sache
1475119610Sache#if defined (HANDLE_MULTIBYTE)
1476119610Sache      pos = (inc > 0) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)
1477119610Sache		      : _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1478119610Sache#else
1479119610Sache      pos += inc;
1480119610Sache#endif
1481119610Sache      do
1482119610Sache	{
1483119610Sache#if defined (HANDLE_MULTIBYTE)
1484119610Sache	  if (_rl_is_mbchar_matched (rl_line_buffer, pos, rl_end, smbchar, len))
1485119610Sache#else
1486119610Sache	  if (rl_line_buffer[pos] == schar)
1487119610Sache#endif
1488119610Sache	    {
1489119610Sache	      count--;
1490119610Sache	      if (dir < 0)
1491119610Sache	        rl_point = (dir == BTO) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)
1492119610Sache					: pos;
1493119610Sache	      else
1494119610Sache		rl_point = (dir == FTO) ? _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)
1495119610Sache					: pos;
1496119610Sache	      break;
1497119610Sache	    }
1498119610Sache#if defined (HANDLE_MULTIBYTE)
1499119610Sache	  prepos = pos;
1500119610Sache#endif
1501119610Sache	}
1502119610Sache#if defined (HANDLE_MULTIBYTE)
1503119610Sache      while ((dir < 0) ? (pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)) != prepos
1504119610Sache		       : (pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)) != prepos);
1505119610Sache#else
1506119610Sache      while ((dir < 0) ? pos-- : ++pos < rl_end);
1507119610Sache#endif
1508119610Sache    }
1509119610Sache  return (0);
1510119610Sache}
1511119610Sache
1512119610Sache/* Search COUNT times for a character read from the current input stream.
1513119610Sache   FDIR is the direction to search if COUNT is non-negative; otherwise
1514119610Sache   the search goes in BDIR.  So much is dependent on HANDLE_MULTIBYTE
1515119610Sache   that there are two separate versions of this function. */
1516119610Sache#if defined (HANDLE_MULTIBYTE)
1517119610Sachestatic int
1518119610Sache_rl_char_search (count, fdir, bdir)
1519119610Sache     int count, fdir, bdir;
1520119610Sache{
1521119610Sache  char mbchar[MB_LEN_MAX];
1522119610Sache  int mb_len;
1523119610Sache
1524119610Sache  mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX);
1525119610Sache
1526173403Sache  if (mb_len <= 0)
1527173403Sache    return -1;
1528173403Sache
1529119610Sache  if (count < 0)
1530119610Sache    return (_rl_char_search_internal (-count, bdir, mbchar, mb_len));
1531119610Sache  else
1532119610Sache    return (_rl_char_search_internal (count, fdir, mbchar, mb_len));
1533119610Sache}
1534119610Sache#else /* !HANDLE_MULTIBYTE */
1535119610Sachestatic int
1536119610Sache_rl_char_search (count, fdir, bdir)
1537119610Sache     int count, fdir, bdir;
1538119610Sache{
1539119610Sache  int c;
1540119610Sache
1541119610Sache  RL_SETSTATE(RL_STATE_MOREINPUT);
1542119610Sache  c = rl_read_key ();
1543119610Sache  RL_UNSETSTATE(RL_STATE_MOREINPUT);
1544119610Sache
1545173403Sache  if (c < 0)
1546173403Sache    return -1;
1547173403Sache
1548119610Sache  if (count < 0)
1549119610Sache    return (_rl_char_search_internal (-count, bdir, c));
1550119610Sache  else
1551119610Sache    return (_rl_char_search_internal (count, fdir, c));
1552119610Sache}
1553119610Sache#endif /* !HANDLE_MULTIBYTE */
1554119610Sache
1555157184Sache#if defined (READLINE_CALLBACKS)
1556157184Sachestatic int
1557157184Sache_rl_char_search_callback (data)
1558157184Sache     _rl_callback_generic_arg *data;
1559157184Sache{
1560157184Sache  _rl_callback_func = 0;
1561157184Sache  _rl_want_redisplay = 1;
1562157184Sache
1563157184Sache  return (_rl_char_search (data->count, data->i1, data->i2));
1564157184Sache}
1565157184Sache#endif
1566157184Sache
1567119610Sacheint
1568119610Sacherl_char_search (count, key)
1569119610Sache     int count, key;
1570119610Sache{
1571157184Sache#if defined (READLINE_CALLBACKS)
1572157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK))
1573157184Sache    {
1574157184Sache      _rl_callback_data = _rl_callback_data_alloc (count);
1575157184Sache      _rl_callback_data->i1 = FFIND;
1576157184Sache      _rl_callback_data->i2 = BFIND;
1577157184Sache      _rl_callback_func = _rl_char_search_callback;
1578157184Sache      return (0);
1579157184Sache    }
1580157184Sache#endif
1581157184Sache
1582119610Sache  return (_rl_char_search (count, FFIND, BFIND));
1583119610Sache}
1584119610Sache
1585119610Sacheint
1586119610Sacherl_backward_char_search (count, key)
1587119610Sache     int count, key;
1588119610Sache{
1589157184Sache#if defined (READLINE_CALLBACKS)
1590157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK))
1591157184Sache    {
1592157184Sache      _rl_callback_data = _rl_callback_data_alloc (count);
1593157184Sache      _rl_callback_data->i1 = BFIND;
1594157184Sache      _rl_callback_data->i2 = FFIND;
1595157184Sache      _rl_callback_func = _rl_char_search_callback;
1596157184Sache      return (0);
1597157184Sache    }
1598157184Sache#endif
1599157184Sache
1600119610Sache  return (_rl_char_search (count, BFIND, FFIND));
1601119610Sache}
1602119610Sache
1603119610Sache/* **************************************************************** */
1604119610Sache/*								    */
1605119610Sache/*		   The Mark and the Region.			    */
1606119610Sache/*								    */
1607119610Sache/* **************************************************************** */
1608119610Sache
1609119610Sache/* Set the mark at POSITION. */
1610119610Sacheint
1611119610Sache_rl_set_mark_at_pos (position)
1612119610Sache     int position;
1613119610Sache{
1614119610Sache  if (position > rl_end)
1615119610Sache    return -1;
1616119610Sache
1617119610Sache  rl_mark = position;
1618119610Sache  return 0;
1619119610Sache}
1620119610Sache
1621119610Sache/* A bindable command to set the mark. */
1622119610Sacheint
1623119610Sacherl_set_mark (count, key)
1624119610Sache     int count, key;
1625119610Sache{
1626119610Sache  return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point));
1627119610Sache}
1628119610Sache
1629119610Sache/* Exchange the position of mark and point. */
1630119610Sacheint
1631119610Sacherl_exchange_point_and_mark (count, key)
1632119610Sache     int count, key;
1633119610Sache{
1634119610Sache  if (rl_mark > rl_end)
1635119610Sache    rl_mark = -1;
1636119610Sache
1637119610Sache  if (rl_mark == -1)
1638119610Sache    {
1639119610Sache      rl_ding ();
1640119610Sache      return -1;
1641119610Sache    }
1642119610Sache  else
1643119610Sache    SWAP (rl_point, rl_mark);
1644119610Sache
1645119610Sache  return 0;
1646119610Sache}
1647