misc.c revision 136644
1/* misc.c -- miscellaneous bindable readline functions. */
2
3/* Copyright (C) 1987-2004 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      /* Can't call with `1' because rl_undo_list might point to an undo
257	 list from a history entry, as in rl_replace_from_history() below. */
258      rl_replace_line (_rl_saved_line_for_history->line, 0);
259      rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data;
260      _rl_free_history_entry (_rl_saved_line_for_history);
261      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
262      rl_point = rl_end;	/* rl_replace_line sets rl_end */
263    }
264  else
265    rl_ding ();
266  return 0;
267}
268
269/* Save the current line in _rl_saved_line_for_history. */
270int
271rl_maybe_save_line ()
272{
273  if (_rl_saved_line_for_history == 0)
274    {
275      _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
276      _rl_saved_line_for_history->line = savestring (rl_line_buffer);
277      _rl_saved_line_for_history->data = (char *)rl_undo_list;
278    }
279  else if (STREQ (rl_line_buffer, _rl_saved_line_for_history->line) == 0)
280    {
281      free (_rl_saved_line_for_history->line);
282      _rl_saved_line_for_history->line = savestring (rl_line_buffer);
283      _rl_saved_line_for_history->data = (char *)rl_undo_list;	/* XXX possible memleak */
284    }
285
286  return 0;
287}
288
289int
290_rl_free_saved_history_line ()
291{
292  if (_rl_saved_line_for_history)
293    {
294      _rl_free_history_entry (_rl_saved_line_for_history);
295      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
296    }
297  return 0;
298}
299
300static void
301_rl_history_set_point ()
302{
303  rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1)
304		? _rl_history_saved_point
305		: rl_end;
306  if (rl_point > rl_end)
307    rl_point = rl_end;
308
309#if defined (VI_MODE)
310  if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap)
311    rl_point = 0;
312#endif /* VI_MODE */
313
314  if (rl_editing_mode == emacs_mode)
315    rl_mark = (rl_point == rl_end ? 0 : rl_end);
316}
317
318void
319rl_replace_from_history (entry, flags)
320     HIST_ENTRY *entry;
321     int flags;			/* currently unused */
322{
323  /* Can't call with `1' because rl_undo_list might point to an undo list
324     from a history entry, just like we're setting up here. */
325  rl_replace_line (entry->line, 0);
326  rl_undo_list = (UNDO_LIST *)entry->data;
327  rl_point = rl_end;
328  rl_mark = 0;
329
330#if defined (VI_MODE)
331  if (rl_editing_mode == vi_mode)
332    {
333      rl_point = 0;
334      rl_mark = rl_end;
335    }
336#endif
337}
338
339/* **************************************************************** */
340/*								    */
341/*			History Commands			    */
342/*								    */
343/* **************************************************************** */
344
345/* Meta-< goes to the start of the history. */
346int
347rl_beginning_of_history (count, key)
348     int count, key;
349{
350  return (rl_get_previous_history (1 + where_history (), key));
351}
352
353/* Meta-> goes to the end of the history.  (The current line). */
354int
355rl_end_of_history (count, key)
356     int count, key;
357{
358  rl_maybe_replace_line ();
359  using_history ();
360  rl_maybe_unsave_line ();
361  return 0;
362}
363
364/* Move down to the next history line. */
365int
366rl_get_next_history (count, key)
367     int count, key;
368{
369  HIST_ENTRY *temp;
370
371  if (count < 0)
372    return (rl_get_previous_history (-count, key));
373
374  if (count == 0)
375    return 0;
376
377  rl_maybe_replace_line ();
378
379  /* either not saved by rl_newline or at end of line, so set appropriately. */
380  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
381    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
382
383  temp = (HIST_ENTRY *)NULL;
384  while (count)
385    {
386      temp = next_history ();
387      if (!temp)
388	break;
389      --count;
390    }
391
392  if (temp == 0)
393    rl_maybe_unsave_line ();
394  else
395    {
396      rl_replace_from_history (temp, 0);
397      _rl_history_set_point ();
398    }
399  return 0;
400}
401
402/* Get the previous item out of our interactive history, making it the current
403   line.  If there is no previous history, just ding. */
404int
405rl_get_previous_history (count, key)
406     int count, key;
407{
408  HIST_ENTRY *old_temp, *temp;
409
410  if (count < 0)
411    return (rl_get_next_history (-count, key));
412
413  if (count == 0)
414    return 0;
415
416  /* either not saved by rl_newline or at end of line, so set appropriately. */
417  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
418    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
419
420  /* If we don't have a line saved, then save this one. */
421  rl_maybe_save_line ();
422
423  /* If the current line has changed, save the changes. */
424  rl_maybe_replace_line ();
425
426  temp = old_temp = (HIST_ENTRY *)NULL;
427  while (count)
428    {
429      temp = previous_history ();
430      if (temp == 0)
431	break;
432
433      old_temp = temp;
434      --count;
435    }
436
437  /* If there was a large argument, and we moved back to the start of the
438     history, that is not an error.  So use the last value found. */
439  if (!temp && old_temp)
440    temp = old_temp;
441
442  if (temp == 0)
443    rl_ding ();
444  else
445    {
446      rl_replace_from_history (temp, 0);
447      _rl_history_set_point ();
448    }
449
450  return 0;
451}
452
453/* **************************************************************** */
454/*								    */
455/*			    Editing Modes			    */
456/*								    */
457/* **************************************************************** */
458/* How to toggle back and forth between editing modes. */
459int
460rl_vi_editing_mode (count, key)
461     int count, key;
462{
463#if defined (VI_MODE)
464  _rl_set_insert_mode (RL_IM_INSERT, 1);	/* vi mode ignores insert mode */
465  rl_editing_mode = vi_mode;
466  rl_vi_insertion_mode (1, key);
467#endif /* VI_MODE */
468
469  return 0;
470}
471
472int
473rl_emacs_editing_mode (count, key)
474     int count, key;
475{
476  rl_editing_mode = emacs_mode;
477  _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */
478  _rl_keymap = emacs_standard_keymap;
479  return 0;
480}
481
482/* Function for the rest of the library to use to set insert/overwrite mode. */
483void
484_rl_set_insert_mode (im, force)
485     int im, force;
486{
487#ifdef CURSOR_MODE
488  _rl_set_cursor (im, force);
489#endif
490
491  rl_insert_mode = im;
492}
493
494/* Toggle overwrite mode.  A positive explicit argument selects overwrite
495   mode.  A negative or zero explicit argument selects insert mode. */
496int
497rl_overwrite_mode (count, key)
498     int count, key;
499{
500  if (rl_explicit_arg == 0)
501    _rl_set_insert_mode (rl_insert_mode ^ 1, 0);
502  else if (count > 0)
503    _rl_set_insert_mode (RL_IM_OVERWRITE, 0);
504  else
505    _rl_set_insert_mode (RL_IM_INSERT, 0);
506
507  return 0;
508}
509