text.c revision 165670
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
860119610Sache#if defined (HANDLE_SIGNALS)
861157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK) == 0)
862157184Sache    _rl_restore_tty_signals ();
863119610Sache#endif
864119610Sache
865119610Sache  return (_rl_insert_char (count, c));
866119610Sache}
867119610Sache
868157184Sache#if defined (READLINE_CALLBACKS)
869157184Sachestatic int
870157184Sache_rl_insert_next_callback (data)
871157184Sache     _rl_callback_generic_arg *data;
872157184Sache{
873157184Sache  int count;
874157184Sache
875157184Sache  count = data->count;
876157184Sache
877157184Sache  /* Deregister function, let rl_callback_read_char deallocate data */
878157184Sache  _rl_callback_func = 0;
879157184Sache  _rl_want_redisplay = 1;
880157184Sache
881157184Sache  return _rl_insert_next (count);
882157184Sache}
883157184Sache#endif
884157184Sache
885157184Sacheint
886157184Sacherl_quoted_insert (count, key)
887157184Sache     int count, key;
888157184Sache{
889157184Sache  /* Let's see...should the callback interface futz with signal handling? */
890157184Sache#if defined (HANDLE_SIGNALS)
891157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK) == 0)
892157184Sache    _rl_disable_tty_signals ();
893157184Sache#endif
894157184Sache
895157184Sache#if defined (READLINE_CALLBACKS)
896157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK))
897157184Sache    {
898157184Sache      _rl_callback_data = _rl_callback_data_alloc (count);
899157184Sache      _rl_callback_func = _rl_insert_next_callback;
900157184Sache      return (0);
901157184Sache    }
902157184Sache#endif
903157184Sache
904157184Sache  return _rl_insert_next (count);
905157184Sache}
906157184Sache
907119610Sache/* Insert a tab character. */
908119610Sacheint
909119610Sacherl_tab_insert (count, key)
910119610Sache     int count, key;
911119610Sache{
912119610Sache  return (_rl_insert_char (count, '\t'));
913119610Sache}
914119610Sache
915119610Sache/* What to do when a NEWLINE is pressed.  We accept the whole line.
916119610Sache   KEY is the key that invoked this command.  I guess it could have
917119610Sache   meaning in the future. */
918119610Sacheint
919119610Sacherl_newline (count, key)
920119610Sache     int count, key;
921119610Sache{
922119610Sache  rl_done = 1;
923119610Sache
924119610Sache  if (_rl_history_preserve_point)
925119610Sache    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
926119610Sache
927119610Sache  RL_SETSTATE(RL_STATE_DONE);
928119610Sache
929119610Sache#if defined (VI_MODE)
930119610Sache  if (rl_editing_mode == vi_mode)
931119610Sache    {
932119610Sache      _rl_vi_done_inserting ();
933136644Sache      if (_rl_vi_textmod_command (_rl_vi_last_command) == 0)	/* XXX */
934136644Sache	_rl_vi_reset_last ();
935119610Sache    }
936119610Sache#endif /* VI_MODE */
937119610Sache
938119610Sache  /* If we've been asked to erase empty lines, suppress the final update,
939119610Sache     since _rl_update_final calls rl_crlf(). */
940119610Sache  if (rl_erase_empty_line && rl_point == 0 && rl_end == 0)
941119610Sache    return 0;
942119610Sache
943119610Sache  if (readline_echoing_p)
944119610Sache    _rl_update_final ();
945119610Sache  return 0;
946119610Sache}
947119610Sache
948119610Sache/* What to do for some uppercase characters, like meta characters,
949119610Sache   and some characters appearing in emacs_ctlx_keymap.  This function
950119610Sache   is just a stub, you bind keys to it and the code in _rl_dispatch ()
951119610Sache   is special cased. */
952119610Sacheint
953119610Sacherl_do_lowercase_version (ignore1, ignore2)
954119610Sache     int ignore1, ignore2;
955119610Sache{
956119610Sache  return 0;
957119610Sache}
958119610Sache
959119610Sache/* This is different from what vi does, so the code's not shared.  Emacs
960119610Sache   rubout in overwrite mode has one oddity:  it replaces a control
961119610Sache   character that's displayed as two characters (^X) with two spaces. */
962119610Sacheint
963119610Sache_rl_overwrite_rubout (count, key)
964119610Sache     int count, key;
965119610Sache{
966119610Sache  int opoint;
967119610Sache  int i, l;
968119610Sache
969119610Sache  if (rl_point == 0)
970119610Sache    {
971119610Sache      rl_ding ();
972119610Sache      return 1;
973119610Sache    }
974119610Sache
975119610Sache  opoint = rl_point;
976119610Sache
977119610Sache  /* L == number of spaces to insert */
978119610Sache  for (i = l = 0; i < count; i++)
979119610Sache    {
980119610Sache      rl_backward_char (1, key);
981119610Sache      l += rl_character_len (rl_line_buffer[rl_point], rl_point);	/* not exactly right */
982119610Sache    }
983119610Sache
984119610Sache  rl_begin_undo_group ();
985119610Sache
986119610Sache  if (count > 1 || rl_explicit_arg)
987119610Sache    rl_kill_text (opoint, rl_point);
988119610Sache  else
989119610Sache    rl_delete_text (opoint, rl_point);
990119610Sache
991119610Sache  /* Emacs puts point at the beginning of the sequence of spaces. */
992136644Sache  if (rl_point < rl_end)
993136644Sache    {
994136644Sache      opoint = rl_point;
995136644Sache      _rl_insert_char (l, ' ');
996136644Sache      rl_point = opoint;
997136644Sache    }
998119610Sache
999119610Sache  rl_end_undo_group ();
1000119610Sache
1001119610Sache  return 0;
1002119610Sache}
1003119610Sache
1004119610Sache/* Rubout the character behind point. */
1005119610Sacheint
1006119610Sacherl_rubout (count, key)
1007119610Sache     int count, key;
1008119610Sache{
1009119610Sache  if (count < 0)
1010119610Sache    return (rl_delete (-count, key));
1011119610Sache
1012119610Sache  if (!rl_point)
1013119610Sache    {
1014119610Sache      rl_ding ();
1015119610Sache      return -1;
1016119610Sache    }
1017119610Sache
1018119610Sache  if (rl_insert_mode == RL_IM_OVERWRITE)
1019119610Sache    return (_rl_overwrite_rubout (count, key));
1020119610Sache
1021119610Sache  return (_rl_rubout_char (count, key));
1022119610Sache}
1023119610Sache
1024119610Sacheint
1025119610Sache_rl_rubout_char (count, key)
1026119610Sache     int count, key;
1027119610Sache{
1028119610Sache  int orig_point;
1029119610Sache  unsigned char c;
1030119610Sache
1031119610Sache  /* Duplicated code because this is called from other parts of the library. */
1032119610Sache  if (count < 0)
1033119610Sache    return (rl_delete (-count, key));
1034119610Sache
1035119610Sache  if (rl_point == 0)
1036119610Sache    {
1037119610Sache      rl_ding ();
1038119610Sache      return -1;
1039119610Sache    }
1040119610Sache
1041157184Sache  orig_point = rl_point;
1042119610Sache  if (count > 1 || rl_explicit_arg)
1043119610Sache    {
1044157184Sache      rl_backward_char (count, key);
1045119610Sache      rl_kill_text (orig_point, rl_point);
1046119610Sache    }
1047157184Sache  else if (MB_CUR_MAX == 1 || rl_byte_oriented)
1048119610Sache    {
1049157184Sache      c = rl_line_buffer[--rl_point];
1050157184Sache      rl_delete_text (rl_point, orig_point);
1051157184Sache      /* The erase-at-end-of-line hack is of questionable merit now. */
1052119610Sache      if (rl_point == rl_end && ISPRINT (c) && _rl_last_c_pos)
1053119610Sache	{
1054119610Sache	  int l;
1055119610Sache	  l = rl_character_len (c, rl_point);
1056119610Sache	  _rl_erase_at_end_of_line (l);
1057119610Sache	}
1058119610Sache    }
1059157184Sache  else
1060157184Sache    {
1061157184Sache      rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1062157184Sache      rl_delete_text (rl_point, orig_point);
1063157184Sache    }
1064119610Sache
1065119610Sache  return 0;
1066119610Sache}
1067119610Sache
1068119610Sache/* Delete the character under the cursor.  Given a numeric argument,
1069119610Sache   kill that many characters instead. */
1070119610Sacheint
1071119610Sacherl_delete (count, key)
1072119610Sache     int count, key;
1073119610Sache{
1074165670Sache  int xpoint;
1075165670Sache
1076119610Sache  if (count < 0)
1077119610Sache    return (_rl_rubout_char (-count, key));
1078119610Sache
1079119610Sache  if (rl_point == rl_end)
1080119610Sache    {
1081119610Sache      rl_ding ();
1082119610Sache      return -1;
1083119610Sache    }
1084119610Sache
1085119610Sache  if (count > 1 || rl_explicit_arg)
1086119610Sache    {
1087165670Sache      xpoint = rl_point;
1088119610Sache      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1089119610Sache	rl_forward_char (count, key);
1090119610Sache      else
1091119610Sache	rl_forward_byte (count, key);
1092119610Sache
1093165670Sache      rl_kill_text (xpoint, rl_point);
1094165670Sache      rl_point = xpoint;
1095119610Sache    }
1096119610Sache  else
1097119610Sache    {
1098165670Sache      xpoint = MB_NEXTCHAR (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
1099165670Sache      rl_delete_text (rl_point, xpoint);
1100119610Sache    }
1101157191Sache  return 0;
1102119610Sache}
1103119610Sache
1104119610Sache/* Delete the character under the cursor, unless the insertion
1105119610Sache   point is at the end of the line, in which case the character
1106119610Sache   behind the cursor is deleted.  COUNT is obeyed and may be used
1107119610Sache   to delete forward or backward that many characters. */
1108119610Sacheint
1109119610Sacherl_rubout_or_delete (count, key)
1110119610Sache     int count, key;
1111119610Sache{
1112119610Sache  if (rl_end != 0 && rl_point == rl_end)
1113119610Sache    return (_rl_rubout_char (count, key));
1114119610Sache  else
1115119610Sache    return (rl_delete (count, key));
1116119610Sache}
1117119610Sache
1118119610Sache/* Delete all spaces and tabs around point. */
1119119610Sacheint
1120119610Sacherl_delete_horizontal_space (count, ignore)
1121119610Sache     int count, ignore;
1122119610Sache{
1123119610Sache  int start = rl_point;
1124119610Sache
1125119610Sache  while (rl_point && whitespace (rl_line_buffer[rl_point - 1]))
1126119610Sache    rl_point--;
1127119610Sache
1128119610Sache  start = rl_point;
1129119610Sache
1130119610Sache  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1131119610Sache    rl_point++;
1132119610Sache
1133119610Sache  if (start != rl_point)
1134119610Sache    {
1135119610Sache      rl_delete_text (start, rl_point);
1136119610Sache      rl_point = start;
1137119610Sache    }
1138157184Sache
1139157184Sache  if (rl_point < 0)
1140157184Sache    rl_point = 0;
1141157184Sache
1142119610Sache  return 0;
1143119610Sache}
1144119610Sache
1145119610Sache/* Like the tcsh editing function delete-char-or-list.  The eof character
1146119610Sache   is caught before this is invoked, so this really does the same thing as
1147119610Sache   delete-char-or-list-or-eof, as long as it's bound to the eof character. */
1148119610Sacheint
1149119610Sacherl_delete_or_show_completions (count, key)
1150119610Sache     int count, key;
1151119610Sache{
1152119610Sache  if (rl_end != 0 && rl_point == rl_end)
1153119610Sache    return (rl_possible_completions (count, key));
1154119610Sache  else
1155119610Sache    return (rl_delete (count, key));
1156119610Sache}
1157119610Sache
1158119610Sache#ifndef RL_COMMENT_BEGIN_DEFAULT
1159119610Sache#define RL_COMMENT_BEGIN_DEFAULT "#"
1160119610Sache#endif
1161119610Sache
1162119610Sache/* Turn the current line into a comment in shell history.
1163119610Sache   A K*rn shell style function. */
1164119610Sacheint
1165119610Sacherl_insert_comment (count, key)
1166119610Sache     int count, key;
1167119610Sache{
1168119610Sache  char *rl_comment_text;
1169119610Sache  int rl_comment_len;
1170119610Sache
1171119610Sache  rl_beg_of_line (1, key);
1172119610Sache  rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT;
1173119610Sache
1174119610Sache  if (rl_explicit_arg == 0)
1175119610Sache    rl_insert_text (rl_comment_text);
1176119610Sache  else
1177119610Sache    {
1178119610Sache      rl_comment_len = strlen (rl_comment_text);
1179119610Sache      if (STREQN (rl_comment_text, rl_line_buffer, rl_comment_len))
1180119610Sache	rl_delete_text (rl_point, rl_point + rl_comment_len);
1181119610Sache      else
1182119610Sache	rl_insert_text (rl_comment_text);
1183119610Sache    }
1184119610Sache
1185119610Sache  (*rl_redisplay_function) ();
1186119610Sache  rl_newline (1, '\n');
1187119610Sache
1188119610Sache  return (0);
1189119610Sache}
1190119610Sache
1191119610Sache/* **************************************************************** */
1192119610Sache/*								    */
1193119610Sache/*			Changing Case				    */
1194119610Sache/*								    */
1195119610Sache/* **************************************************************** */
1196119610Sache
1197119610Sache/* The three kinds of things that we know how to do. */
1198119610Sache#define UpCase 1
1199119610Sache#define DownCase 2
1200119610Sache#define CapCase 3
1201119610Sache
1202119610Sache/* Uppercase the word at point. */
1203119610Sacheint
1204119610Sacherl_upcase_word (count, key)
1205119610Sache     int count, key;
1206119610Sache{
1207119610Sache  return (rl_change_case (count, UpCase));
1208119610Sache}
1209119610Sache
1210119610Sache/* Lowercase the word at point. */
1211119610Sacheint
1212119610Sacherl_downcase_word (count, key)
1213119610Sache     int count, key;
1214119610Sache{
1215119610Sache  return (rl_change_case (count, DownCase));
1216119610Sache}
1217119610Sache
1218119610Sache/* Upcase the first letter, downcase the rest. */
1219119610Sacheint
1220119610Sacherl_capitalize_word (count, key)
1221119610Sache     int count, key;
1222119610Sache{
1223119610Sache return (rl_change_case (count, CapCase));
1224119610Sache}
1225119610Sache
1226119610Sache/* The meaty function.
1227119610Sache   Change the case of COUNT words, performing OP on them.
1228119610Sache   OP is one of UpCase, DownCase, or CapCase.
1229119610Sache   If a negative argument is given, leave point where it started,
1230119610Sache   otherwise, leave it where it moves to. */
1231119610Sachestatic int
1232119610Sacherl_change_case (count, op)
1233119610Sache     int count, op;
1234119610Sache{
1235157184Sache  int start, next, end;
1236157184Sache  int inword, c, nc, nop;
1237157184Sache#if defined (HANDLE_MULTIBYTE)
1238157184Sache  wchar_t wc, nwc;
1239157184Sache  char mb[MB_LEN_MAX+1];
1240165670Sache  int mlen;
1241165670Sache  mbstate_t mps;
1242157184Sache#endif
1243119610Sache
1244119610Sache  start = rl_point;
1245119610Sache  rl_forward_word (count, 0);
1246119610Sache  end = rl_point;
1247119610Sache
1248157184Sache  if (op != UpCase && op != DownCase && op != CapCase)
1249157184Sache    {
1250157184Sache      rl_ding ();
1251157184Sache      return -1;
1252157184Sache    }
1253157184Sache
1254119610Sache  if (count < 0)
1255119610Sache    SWAP (start, end);
1256119610Sache
1257157184Sache#if defined (HANDLE_MULTIBYTE)
1258165670Sache  memset (&mps, 0, sizeof (mbstate_t));
1259157184Sache#endif
1260157184Sache
1261119610Sache  /* We are going to modify some text, so let's prepare to undo it. */
1262119610Sache  rl_modifying (start, end);
1263119610Sache
1264157184Sache  inword = 0;
1265157184Sache  while (start < end)
1266119610Sache    {
1267157184Sache      c = _rl_char_value (rl_line_buffer, start);
1268157184Sache      /*  This assumes that the upper and lower case versions are the same width. */
1269157184Sache      next = MB_NEXTCHAR (rl_line_buffer, start, 1, MB_FIND_NONZERO);
1270157184Sache
1271157184Sache      if (_rl_walphabetic (c) == 0)
1272119610Sache	{
1273157184Sache	  inword = 0;
1274157184Sache	  start = next;
1275157184Sache	  continue;
1276157184Sache	}
1277119610Sache
1278157184Sache      if (op == CapCase)
1279157184Sache	{
1280157184Sache	  nop = inword ? DownCase : UpCase;
1281157184Sache	  inword = 1;
1282157184Sache	}
1283157184Sache      else
1284157184Sache	nop = op;
1285157184Sache      if (MB_CUR_MAX == 1 || rl_byte_oriented || isascii (c))
1286157184Sache	{
1287157184Sache	  nc = (nop == UpCase) ? _rl_to_upper (c) : _rl_to_lower (c);
1288157184Sache	  rl_line_buffer[start] = nc;
1289157184Sache	}
1290157184Sache#if defined (HANDLE_MULTIBYTE)
1291157184Sache      else
1292157184Sache	{
1293165670Sache	  mbrtowc (&wc, rl_line_buffer + start, end - start, &mps);
1294157184Sache	  nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc);
1295157184Sache	  if  (nwc != wc)	/*  just skip unchanged characters */
1296157184Sache	    {
1297165670Sache	      mlen = wcrtomb (mb, nwc, &mps);
1298165670Sache	      if (mlen > 0)
1299165670Sache		mb[mlen] = '\0';
1300157184Sache	      /* Assume the same width */
1301165670Sache	      strncpy (rl_line_buffer + start, mb, mlen);
1302157184Sache	    }
1303157184Sache	}
1304157184Sache#endif
1305119610Sache
1306157184Sache      start = next;
1307157184Sache    }
1308119610Sache
1309119610Sache  rl_point = end;
1310119610Sache  return 0;
1311119610Sache}
1312119610Sache
1313119610Sache/* **************************************************************** */
1314119610Sache/*								    */
1315119610Sache/*			Transposition				    */
1316119610Sache/*								    */
1317119610Sache/* **************************************************************** */
1318119610Sache
1319119610Sache/* Transpose the words at point.  If point is at the end of the line,
1320119610Sache   transpose the two words before point. */
1321119610Sacheint
1322119610Sacherl_transpose_words (count, key)
1323119610Sache     int count, key;
1324119610Sache{
1325119610Sache  char *word1, *word2;
1326119610Sache  int w1_beg, w1_end, w2_beg, w2_end;
1327119610Sache  int orig_point = rl_point;
1328119610Sache
1329119610Sache  if (!count)
1330119610Sache    return 0;
1331119610Sache
1332119610Sache  /* Find the two words. */
1333119610Sache  rl_forward_word (count, key);
1334119610Sache  w2_end = rl_point;
1335119610Sache  rl_backward_word (1, key);
1336119610Sache  w2_beg = rl_point;
1337119610Sache  rl_backward_word (count, key);
1338119610Sache  w1_beg = rl_point;
1339119610Sache  rl_forward_word (1, key);
1340119610Sache  w1_end = rl_point;
1341119610Sache
1342119610Sache  /* Do some check to make sure that there really are two words. */
1343119610Sache  if ((w1_beg == w2_beg) || (w2_beg < w1_end))
1344119610Sache    {
1345119610Sache      rl_ding ();
1346119610Sache      rl_point = orig_point;
1347119610Sache      return -1;
1348119610Sache    }
1349119610Sache
1350119610Sache  /* Get the text of the words. */
1351119610Sache  word1 = rl_copy_text (w1_beg, w1_end);
1352119610Sache  word2 = rl_copy_text (w2_beg, w2_end);
1353119610Sache
1354119610Sache  /* We are about to do many insertions and deletions.  Remember them
1355119610Sache     as one operation. */
1356119610Sache  rl_begin_undo_group ();
1357119610Sache
1358119610Sache  /* Do the stuff at word2 first, so that we don't have to worry
1359119610Sache     about word1 moving. */
1360119610Sache  rl_point = w2_beg;
1361119610Sache  rl_delete_text (w2_beg, w2_end);
1362119610Sache  rl_insert_text (word1);
1363119610Sache
1364119610Sache  rl_point = w1_beg;
1365119610Sache  rl_delete_text (w1_beg, w1_end);
1366119610Sache  rl_insert_text (word2);
1367119610Sache
1368119610Sache  /* This is exactly correct since the text before this point has not
1369119610Sache     changed in length. */
1370119610Sache  rl_point = w2_end;
1371119610Sache
1372119610Sache  /* I think that does it. */
1373119610Sache  rl_end_undo_group ();
1374119610Sache  free (word1);
1375119610Sache  free (word2);
1376119610Sache
1377119610Sache  return 0;
1378119610Sache}
1379119610Sache
1380119610Sache/* Transpose the characters at point.  If point is at the end of the line,
1381119610Sache   then transpose the characters before point. */
1382119610Sacheint
1383119610Sacherl_transpose_chars (count, key)
1384119610Sache     int count, key;
1385119610Sache{
1386119610Sache#if defined (HANDLE_MULTIBYTE)
1387119610Sache  char *dummy;
1388157184Sache  int i;
1389119610Sache#else
1390119610Sache  char dummy[2];
1391119610Sache#endif
1392157184Sache  int char_length, prev_point;
1393119610Sache
1394119610Sache  if (count == 0)
1395119610Sache    return 0;
1396119610Sache
1397119610Sache  if (!rl_point || rl_end < 2)
1398119610Sache    {
1399119610Sache      rl_ding ();
1400119610Sache      return -1;
1401119610Sache    }
1402119610Sache
1403119610Sache  rl_begin_undo_group ();
1404119610Sache
1405119610Sache  if (rl_point == rl_end)
1406119610Sache    {
1407157184Sache      rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1408119610Sache      count = 1;
1409119610Sache    }
1410119610Sache
1411119610Sache  prev_point = rl_point;
1412157184Sache  rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1413119610Sache
1414119610Sache#if defined (HANDLE_MULTIBYTE)
1415119610Sache  char_length = prev_point - rl_point;
1416119610Sache  dummy = (char *)xmalloc (char_length + 1);
1417119610Sache  for (i = 0; i < char_length; i++)
1418119610Sache    dummy[i] = rl_line_buffer[rl_point + i];
1419119610Sache  dummy[i] = '\0';
1420119610Sache#else
1421119610Sache  dummy[0] = rl_line_buffer[rl_point];
1422119610Sache  dummy[char_length = 1] = '\0';
1423119610Sache#endif
1424119610Sache
1425119610Sache  rl_delete_text (rl_point, rl_point + char_length);
1426119610Sache
1427119610Sache  rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1428119610Sache
1429119610Sache  _rl_fix_point (0);
1430119610Sache  rl_insert_text (dummy);
1431119610Sache  rl_end_undo_group ();
1432119610Sache
1433119610Sache#if defined (HANDLE_MULTIBYTE)
1434119610Sache  free (dummy);
1435119610Sache#endif
1436119610Sache
1437119610Sache  return 0;
1438119610Sache}
1439119610Sache
1440119610Sache/* **************************************************************** */
1441119610Sache/*								    */
1442119610Sache/*			Character Searching			    */
1443119610Sache/*								    */
1444119610Sache/* **************************************************************** */
1445119610Sache
1446119610Sacheint
1447119610Sache#if defined (HANDLE_MULTIBYTE)
1448119610Sache_rl_char_search_internal (count, dir, smbchar, len)
1449119610Sache     int count, dir;
1450119610Sache     char *smbchar;
1451119610Sache     int len;
1452119610Sache#else
1453119610Sache_rl_char_search_internal (count, dir, schar)
1454119610Sache     int count, dir, schar;
1455119610Sache#endif
1456119610Sache{
1457119610Sache  int pos, inc;
1458119610Sache#if defined (HANDLE_MULTIBYTE)
1459119610Sache  int prepos;
1460119610Sache#endif
1461119610Sache
1462119610Sache  pos = rl_point;
1463119610Sache  inc = (dir < 0) ? -1 : 1;
1464119610Sache  while (count)
1465119610Sache    {
1466119610Sache      if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end))
1467119610Sache	{
1468119610Sache	  rl_ding ();
1469119610Sache	  return -1;
1470119610Sache	}
1471119610Sache
1472119610Sache#if defined (HANDLE_MULTIBYTE)
1473119610Sache      pos = (inc > 0) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)
1474119610Sache		      : _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1475119610Sache#else
1476119610Sache      pos += inc;
1477119610Sache#endif
1478119610Sache      do
1479119610Sache	{
1480119610Sache#if defined (HANDLE_MULTIBYTE)
1481119610Sache	  if (_rl_is_mbchar_matched (rl_line_buffer, pos, rl_end, smbchar, len))
1482119610Sache#else
1483119610Sache	  if (rl_line_buffer[pos] == schar)
1484119610Sache#endif
1485119610Sache	    {
1486119610Sache	      count--;
1487119610Sache	      if (dir < 0)
1488119610Sache	        rl_point = (dir == BTO) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)
1489119610Sache					: pos;
1490119610Sache	      else
1491119610Sache		rl_point = (dir == FTO) ? _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)
1492119610Sache					: pos;
1493119610Sache	      break;
1494119610Sache	    }
1495119610Sache#if defined (HANDLE_MULTIBYTE)
1496119610Sache	  prepos = pos;
1497119610Sache#endif
1498119610Sache	}
1499119610Sache#if defined (HANDLE_MULTIBYTE)
1500119610Sache      while ((dir < 0) ? (pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)) != prepos
1501119610Sache		       : (pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)) != prepos);
1502119610Sache#else
1503119610Sache      while ((dir < 0) ? pos-- : ++pos < rl_end);
1504119610Sache#endif
1505119610Sache    }
1506119610Sache  return (0);
1507119610Sache}
1508119610Sache
1509119610Sache/* Search COUNT times for a character read from the current input stream.
1510119610Sache   FDIR is the direction to search if COUNT is non-negative; otherwise
1511119610Sache   the search goes in BDIR.  So much is dependent on HANDLE_MULTIBYTE
1512119610Sache   that there are two separate versions of this function. */
1513119610Sache#if defined (HANDLE_MULTIBYTE)
1514119610Sachestatic int
1515119610Sache_rl_char_search (count, fdir, bdir)
1516119610Sache     int count, fdir, bdir;
1517119610Sache{
1518119610Sache  char mbchar[MB_LEN_MAX];
1519119610Sache  int mb_len;
1520119610Sache
1521119610Sache  mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX);
1522119610Sache
1523119610Sache  if (count < 0)
1524119610Sache    return (_rl_char_search_internal (-count, bdir, mbchar, mb_len));
1525119610Sache  else
1526119610Sache    return (_rl_char_search_internal (count, fdir, mbchar, mb_len));
1527119610Sache}
1528119610Sache#else /* !HANDLE_MULTIBYTE */
1529119610Sachestatic int
1530119610Sache_rl_char_search (count, fdir, bdir)
1531119610Sache     int count, fdir, bdir;
1532119610Sache{
1533119610Sache  int c;
1534119610Sache
1535119610Sache  RL_SETSTATE(RL_STATE_MOREINPUT);
1536119610Sache  c = rl_read_key ();
1537119610Sache  RL_UNSETSTATE(RL_STATE_MOREINPUT);
1538119610Sache
1539119610Sache  if (count < 0)
1540119610Sache    return (_rl_char_search_internal (-count, bdir, c));
1541119610Sache  else
1542119610Sache    return (_rl_char_search_internal (count, fdir, c));
1543119610Sache}
1544119610Sache#endif /* !HANDLE_MULTIBYTE */
1545119610Sache
1546157184Sache#if defined (READLINE_CALLBACKS)
1547157184Sachestatic int
1548157184Sache_rl_char_search_callback (data)
1549157184Sache     _rl_callback_generic_arg *data;
1550157184Sache{
1551157184Sache  _rl_callback_func = 0;
1552157184Sache  _rl_want_redisplay = 1;
1553157184Sache
1554157184Sache  return (_rl_char_search (data->count, data->i1, data->i2));
1555157184Sache}
1556157184Sache#endif
1557157184Sache
1558119610Sacheint
1559119610Sacherl_char_search (count, key)
1560119610Sache     int count, key;
1561119610Sache{
1562157184Sache#if defined (READLINE_CALLBACKS)
1563157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK))
1564157184Sache    {
1565157184Sache      _rl_callback_data = _rl_callback_data_alloc (count);
1566157184Sache      _rl_callback_data->i1 = FFIND;
1567157184Sache      _rl_callback_data->i2 = BFIND;
1568157184Sache      _rl_callback_func = _rl_char_search_callback;
1569157184Sache      return (0);
1570157184Sache    }
1571157184Sache#endif
1572157184Sache
1573119610Sache  return (_rl_char_search (count, FFIND, BFIND));
1574119610Sache}
1575119610Sache
1576119610Sacheint
1577119610Sacherl_backward_char_search (count, key)
1578119610Sache     int count, key;
1579119610Sache{
1580157184Sache#if defined (READLINE_CALLBACKS)
1581157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK))
1582157184Sache    {
1583157184Sache      _rl_callback_data = _rl_callback_data_alloc (count);
1584157184Sache      _rl_callback_data->i1 = BFIND;
1585157184Sache      _rl_callback_data->i2 = FFIND;
1586157184Sache      _rl_callback_func = _rl_char_search_callback;
1587157184Sache      return (0);
1588157184Sache    }
1589157184Sache#endif
1590157184Sache
1591119610Sache  return (_rl_char_search (count, BFIND, FFIND));
1592119610Sache}
1593119610Sache
1594119610Sache/* **************************************************************** */
1595119610Sache/*								    */
1596119610Sache/*		   The Mark and the Region.			    */
1597119610Sache/*								    */
1598119610Sache/* **************************************************************** */
1599119610Sache
1600119610Sache/* Set the mark at POSITION. */
1601119610Sacheint
1602119610Sache_rl_set_mark_at_pos (position)
1603119610Sache     int position;
1604119610Sache{
1605119610Sache  if (position > rl_end)
1606119610Sache    return -1;
1607119610Sache
1608119610Sache  rl_mark = position;
1609119610Sache  return 0;
1610119610Sache}
1611119610Sache
1612119610Sache/* A bindable command to set the mark. */
1613119610Sacheint
1614119610Sacherl_set_mark (count, key)
1615119610Sache     int count, key;
1616119610Sache{
1617119610Sache  return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point));
1618119610Sache}
1619119610Sache
1620119610Sache/* Exchange the position of mark and point. */
1621119610Sacheint
1622119610Sacherl_exchange_point_and_mark (count, key)
1623119610Sache     int count, key;
1624119610Sache{
1625119610Sache  if (rl_mark > rl_end)
1626119610Sache    rl_mark = -1;
1627119610Sache
1628119610Sache  if (rl_mark == -1)
1629119610Sache    {
1630119610Sache      rl_ding ();
1631119610Sache      return -1;
1632119610Sache    }
1633119610Sache  else
1634119610Sache    SWAP (rl_point, rl_mark);
1635119610Sache
1636119610Sache  return 0;
1637119610Sache}
1638