1/* misc.c -- miscellaneous bindable readline functions. */
2
3/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
4
5   This file is part of the GNU Readline Library, a library for
6   reading lines of text with interactive input and history editing.
7
8   The GNU Readline Library is free software; you can redistribute it
9   and/or modify it under the terms of the GNU General Public License
10   as published by the Free Software Foundation; either version 2, or
11   (at your option) any later version.
12
13   The GNU Readline Library is distributed in the hope that it will be
14   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   The GNU General Public License is often shipped with GNU software, and
19   is generally kept in a file called COPYING or LICENSE.  If you do not
20   have a copy of the license, write to the Free Software Foundation,
21   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22#define READLINE_LIBRARY
23
24#if defined (HAVE_CONFIG_H)
25#  include <config.h>
26#endif
27
28#if defined (HAVE_UNISTD_H)
29#  include <unistd.h>
30#endif /* HAVE_UNISTD_H */
31
32#if defined (HAVE_STDLIB_H)
33#  include <stdlib.h>
34#else
35#  include "ansi_stdlib.h"
36#endif /* HAVE_STDLIB_H */
37
38#if defined (HAVE_LOCALE_H)
39#  include <locale.h>
40#endif
41
42#include <stdio.h>
43
44/* System-specific feature definitions and include files. */
45#include "rldefs.h"
46#include "rlmbutil.h"
47
48/* Some standard library routines. */
49#include "readline.h"
50#include "history.h"
51
52#include "rlprivate.h"
53#include "rlshell.h"
54#include "xmalloc.h"
55
56static int rl_digit_loop PARAMS((void));
57static void _rl_history_set_point PARAMS((void));
58
59/* Forward declarations used in this file */
60void _rl_free_history_entry PARAMS((HIST_ENTRY *));
61
62/* If non-zero, rl_get_previous_history and rl_get_next_history attempt
63   to preserve the value of rl_point from line to line. */
64int _rl_history_preserve_point = 0;
65
66/* Saved target point for when _rl_history_preserve_point is set.  Special
67   value of -1 means that point is at the end of the line. */
68int _rl_history_saved_point = -1;
69
70/* **************************************************************** */
71/*								    */
72/*			Numeric Arguments			    */
73/*								    */
74/* **************************************************************** */
75
76/* Handle C-u style numeric args, as well as M--, and M-digits. */
77static int
78rl_digit_loop ()
79{
80  int key, c, sawminus, sawdigits;
81
82  rl_save_prompt ();
83
84  RL_SETSTATE(RL_STATE_NUMERICARG);
85  sawminus = sawdigits = 0;
86  while (1)
87    {
88      if (rl_numeric_arg > 1000000)
89	{
90	  sawdigits = rl_explicit_arg = rl_numeric_arg = 0;
91	  rl_ding ();
92	  rl_restore_prompt ();
93	  rl_clear_message ();
94	  RL_UNSETSTATE(RL_STATE_NUMERICARG);
95	  return 1;
96	}
97      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
98      RL_SETSTATE(RL_STATE_MOREINPUT);
99      key = c = rl_read_key ();
100      RL_UNSETSTATE(RL_STATE_MOREINPUT);
101
102      if (c < 0)
103	{
104	  _rl_abort_internal ();
105	  return -1;
106	}
107
108      /* If we see a key bound to `universal-argument' after seeing digits,
109	 it ends the argument but is otherwise ignored. */
110      if (_rl_keymap[c].type == ISFUNC &&
111	  _rl_keymap[c].function == rl_universal_argument)
112	{
113	  if (sawdigits == 0)
114	    {
115	      rl_numeric_arg *= 4;
116	      continue;
117	    }
118	  else
119	    {
120	      RL_SETSTATE(RL_STATE_MOREINPUT);
121	      key = rl_read_key ();
122	      RL_UNSETSTATE(RL_STATE_MOREINPUT);
123	      rl_restore_prompt ();
124	      rl_clear_message ();
125	      RL_UNSETSTATE(RL_STATE_NUMERICARG);
126	      return (_rl_dispatch (key, _rl_keymap));
127	    }
128	}
129
130      c = UNMETA (c);
131
132      if (_rl_digit_p (c))
133	{
134	  rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0';
135	  sawdigits = rl_explicit_arg = 1;
136	}
137      else if (c == '-' && rl_explicit_arg == 0)
138	{
139	  rl_numeric_arg = sawminus = 1;
140	  rl_arg_sign = -1;
141	}
142      else
143	{
144	  /* Make M-- command equivalent to M--1 command. */
145	  if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0)
146	    rl_explicit_arg = 1;
147	  rl_restore_prompt ();
148	  rl_clear_message ();
149	  RL_UNSETSTATE(RL_STATE_NUMERICARG);
150	  return (_rl_dispatch (key, _rl_keymap));
151	}
152    }
153
154  /*NOTREACHED*/
155}
156
157/* Add the current digit to the argument in progress. */
158int
159rl_digit_argument (ignore, key)
160     int ignore, key;
161{
162  rl_execute_next (key);
163  return (rl_digit_loop ());
164}
165
166/* What to do when you abort reading an argument. */
167int
168rl_discard_argument ()
169{
170  rl_ding ();
171  rl_clear_message ();
172  _rl_init_argument ();
173  return 0;
174}
175
176/* Create a default argument. */
177int
178_rl_init_argument ()
179{
180  rl_numeric_arg = rl_arg_sign = 1;
181  rl_explicit_arg = 0;
182  return 0;
183}
184
185/* C-u, universal argument.  Multiply the current argument by 4.
186   Read a key.  If the key has nothing to do with arguments, then
187   dispatch on it.  If the key is the abort character then abort. */
188int
189rl_universal_argument (count, key)
190     int count, key;
191{
192  rl_numeric_arg *= 4;
193  return (rl_digit_loop ());
194}
195
196/* **************************************************************** */
197/*								    */
198/*			History Utilities			    */
199/*								    */
200/* **************************************************************** */
201
202/* We already have a history library, and that is what we use to control
203   the history features of readline.  This is our local interface to
204   the history mechanism. */
205
206/* While we are editing the history, this is the saved
207   version of the original line. */
208HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
209
210/* Set the history pointer back to the last entry in the history. */
211void
212_rl_start_using_history ()
213{
214  using_history ();
215  if (_rl_saved_line_for_history)
216    _rl_free_history_entry (_rl_saved_line_for_history);
217
218  _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
219}
220
221/* Free the contents (and containing structure) of a HIST_ENTRY. */
222void
223_rl_free_history_entry (entry)
224     HIST_ENTRY *entry;
225{
226  if (entry == 0)
227    return;
228  if (entry->line)
229    free (entry->line);
230  free (entry);
231}
232
233/* Perhaps put back the current line if it has changed. */
234int
235rl_maybe_replace_line ()
236{
237  HIST_ENTRY *temp;
238
239  temp = current_history ();
240  /* If the current line has changed, save the changes. */
241  if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list))
242    {
243      temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
244      free (temp->line);
245      free (temp);
246    }
247  return 0;
248}
249
250/* Restore the _rl_saved_line_for_history if there is one. */
251int
252rl_maybe_unsave_line ()
253{
254  if (_rl_saved_line_for_history)
255    {
256      rl_replace_line (_rl_saved_line_for_history->line, 0);
257      rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data;
258      _rl_free_history_entry (_rl_saved_line_for_history);
259      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
260      rl_point = rl_end;	/* rl_replace_line sets rl_end */
261    }
262  else
263    rl_ding ();
264  return 0;
265}
266
267/* Save the current line in _rl_saved_line_for_history. */
268int
269rl_maybe_save_line ()
270{
271  if (_rl_saved_line_for_history == 0)
272    {
273      _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
274      _rl_saved_line_for_history->line = savestring (rl_line_buffer);
275      _rl_saved_line_for_history->data = (char *)rl_undo_list;
276    }
277  return 0;
278}
279
280int
281_rl_free_saved_history_line ()
282{
283  if (_rl_saved_line_for_history)
284    {
285      _rl_free_history_entry (_rl_saved_line_for_history);
286      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
287    }
288  return 0;
289}
290
291static void
292_rl_history_set_point ()
293{
294  rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1)
295		? _rl_history_saved_point
296		: rl_end;
297  if (rl_point > rl_end)
298    rl_point = rl_end;
299
300#if defined (VI_MODE)
301  if (rl_editing_mode == vi_mode)
302    rl_point = 0;
303#endif /* VI_MODE */
304
305  if (rl_editing_mode == emacs_mode)
306    rl_mark = (rl_point == rl_end ? 0 : rl_end);
307}
308
309void
310rl_replace_from_history (entry, flags)
311     HIST_ENTRY *entry;
312     int flags;			/* currently unused */
313{
314  rl_replace_line (entry->line, 0);
315  rl_undo_list = (UNDO_LIST *)entry->data;
316  rl_point = rl_end;
317  rl_mark = 0;
318
319#if defined (VI_MODE)
320  if (rl_editing_mode == vi_mode)
321    {
322      rl_point = 0;
323      rl_mark = rl_end;
324    }
325#endif
326}
327
328/* **************************************************************** */
329/*								    */
330/*			History Commands			    */
331/*								    */
332/* **************************************************************** */
333
334/* Meta-< goes to the start of the history. */
335int
336rl_beginning_of_history (count, key)
337     int count, key;
338{
339  return (rl_get_previous_history (1 + where_history (), key));
340}
341
342/* Meta-> goes to the end of the history.  (The current line). */
343int
344rl_end_of_history (count, key)
345     int count, key;
346{
347  rl_maybe_replace_line ();
348  using_history ();
349  rl_maybe_unsave_line ();
350  return 0;
351}
352
353/* Move down to the next history line. */
354int
355rl_get_next_history (count, key)
356     int count, key;
357{
358  HIST_ENTRY *temp;
359
360  if (count < 0)
361    return (rl_get_previous_history (-count, key));
362
363  if (count == 0)
364    return 0;
365
366  rl_maybe_replace_line ();
367
368  /* either not saved by rl_newline or at end of line, so set appropriately. */
369  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
370    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
371
372  temp = (HIST_ENTRY *)NULL;
373  while (count)
374    {
375      temp = next_history ();
376      if (!temp)
377	break;
378      --count;
379    }
380
381  if (temp == 0)
382    rl_maybe_unsave_line ();
383  else
384    {
385      rl_replace_from_history (temp, 0);
386      _rl_history_set_point ();
387    }
388  return 0;
389}
390
391/* Get the previous item out of our interactive history, making it the current
392   line.  If there is no previous history, just ding. */
393int
394rl_get_previous_history (count, key)
395     int count, key;
396{
397  HIST_ENTRY *old_temp, *temp;
398
399  if (count < 0)
400    return (rl_get_next_history (-count, key));
401
402  if (count == 0)
403    return 0;
404
405  /* either not saved by rl_newline or at end of line, so set appropriately. */
406  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
407    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
408
409  /* If we don't have a line saved, then save this one. */
410  rl_maybe_save_line ();
411
412  /* If the current line has changed, save the changes. */
413  rl_maybe_replace_line ();
414
415  temp = old_temp = (HIST_ENTRY *)NULL;
416  while (count)
417    {
418      temp = previous_history ();
419      if (temp == 0)
420	break;
421
422      old_temp = temp;
423      --count;
424    }
425
426  /* If there was a large argument, and we moved back to the start of the
427     history, that is not an error.  So use the last value found. */
428  if (!temp && old_temp)
429    temp = old_temp;
430
431  if (temp == 0)
432    rl_ding ();
433  else
434    {
435      rl_replace_from_history (temp, 0);
436      _rl_history_set_point ();
437    }
438  return 0;
439}
440
441/* **************************************************************** */
442/*								    */
443/*			    Editing Modes			    */
444/*								    */
445/* **************************************************************** */
446/* How to toggle back and forth between editing modes. */
447int
448rl_vi_editing_mode (count, key)
449     int count, key;
450{
451#if defined (VI_MODE)
452  _rl_set_insert_mode (RL_IM_INSERT, 1);	/* vi mode ignores insert mode */
453  rl_editing_mode = vi_mode;
454  rl_vi_insertion_mode (1, key);
455#endif /* VI_MODE */
456
457  return 0;
458}
459
460int
461rl_emacs_editing_mode (count, key)
462     int count, key;
463{
464  rl_editing_mode = emacs_mode;
465  _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */
466  _rl_keymap = emacs_standard_keymap;
467  return 0;
468}
469
470/* Function for the rest of the library to use to set insert/overwrite mode. */
471void
472_rl_set_insert_mode (im, force)
473     int im, force;
474{
475#ifdef CURSOR_MODE
476  _rl_set_cursor (im, force);
477#endif
478
479  rl_insert_mode = im;
480}
481
482/* Toggle overwrite mode.  A positive explicit argument selects overwrite
483   mode.  A negative or zero explicit argument selects insert mode. */
484int
485rl_overwrite_mode (count, key)
486     int count, key;
487{
488  if (rl_explicit_arg == 0)
489    _rl_set_insert_mode (rl_insert_mode ^ 1, 0);
490  else if (count > 0)
491    _rl_set_insert_mode (RL_IM_OVERWRITE, 0);
492  else
493    _rl_set_insert_mode (RL_IM_INSERT, 0);
494
495  return 0;
496}
497