1/* misc.c -- miscellaneous bindable readline functions. */
2
3/* Copyright (C) 1987-2005 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_rl_arg_cxt _rl_argcxt;
67
68/* Saved target point for when _rl_history_preserve_point is set.  Special
69   value of -1 means that point is at the end of the line. */
70int _rl_history_saved_point = -1;
71
72/* **************************************************************** */
73/*								    */
74/*			Numeric Arguments			    */
75/*								    */
76/* **************************************************************** */
77
78int
79_rl_arg_overflow ()
80{
81  if (rl_numeric_arg > 1000000)
82    {
83      _rl_argcxt = 0;
84      rl_explicit_arg = rl_numeric_arg = 0;
85      rl_ding ();
86      rl_restore_prompt ();
87      rl_clear_message ();
88      RL_UNSETSTATE(RL_STATE_NUMERICARG);
89      return 1;
90    }
91  return 0;
92}
93
94void
95_rl_arg_init ()
96{
97  rl_save_prompt ();
98  _rl_argcxt = 0;
99  RL_SETSTATE(RL_STATE_NUMERICARG);
100}
101
102int
103_rl_arg_getchar ()
104{
105  int c;
106
107  rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
108  RL_SETSTATE(RL_STATE_MOREINPUT);
109  c = rl_read_key ();
110  RL_UNSETSTATE(RL_STATE_MOREINPUT);
111
112  return c;
113}
114
115/* Process C as part of the current numeric argument.  Return -1 if the
116   argument should be aborted, 0 if we should not read any more chars, and
117   1 if we should continue to read chars. */
118int
119_rl_arg_dispatch (cxt, c)
120     _rl_arg_cxt cxt;
121     int c;
122{
123  int key, r;
124
125  key = c;
126
127  /* If we see a key bound to `universal-argument' after seeing digits,
128      it ends the argument but is otherwise ignored. */
129  if (_rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
130    {
131      if ((cxt & NUM_SAWDIGITS) == 0)
132	{
133	  rl_numeric_arg *= 4;
134	  return 1;
135	}
136      else if (RL_ISSTATE (RL_STATE_CALLBACK))
137        {
138          _rl_argcxt |= NUM_READONE;
139          return 0;	/* XXX */
140        }
141      else
142	{
143	  RL_SETSTATE(RL_STATE_MOREINPUT);
144	  key = rl_read_key ();
145	  RL_UNSETSTATE(RL_STATE_MOREINPUT);
146	  rl_restore_prompt ();
147	  rl_clear_message ();
148	  RL_UNSETSTATE(RL_STATE_NUMERICARG);
149	  return (_rl_dispatch (key, _rl_keymap));
150	}
151    }
152
153  c = UNMETA (c);
154
155  if (_rl_digit_p (c))
156    {
157      r = _rl_digit_value (c);
158      rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) +  r : r;
159      rl_explicit_arg = 1;
160      _rl_argcxt |= NUM_SAWDIGITS;
161    }
162  else if (c == '-' && rl_explicit_arg == 0)
163    {
164      rl_numeric_arg = 1;
165      _rl_argcxt |= NUM_SAWMINUS;
166      rl_arg_sign = -1;
167    }
168  else
169    {
170      /* Make M-- command equivalent to M--1 command. */
171      if ((_rl_argcxt & NUM_SAWMINUS) && rl_numeric_arg == 1 && rl_explicit_arg == 0)
172	rl_explicit_arg = 1;
173      rl_restore_prompt ();
174      rl_clear_message ();
175      RL_UNSETSTATE(RL_STATE_NUMERICARG);
176
177      r = _rl_dispatch (key, _rl_keymap);
178      if (RL_ISSTATE (RL_STATE_CALLBACK))
179	{
180	  /* At worst, this will cause an extra redisplay.  Otherwise,
181	     we have to wait until the next character comes in. */
182	  if (rl_done == 0)
183	    (*rl_redisplay_function) ();
184	  r = 0;
185	}
186      return r;
187    }
188
189  return 1;
190}
191
192/* Handle C-u style numeric args, as well as M--, and M-digits. */
193static int
194rl_digit_loop ()
195{
196  int c, r;
197
198  while (1)
199    {
200      if (_rl_arg_overflow ())
201	return 1;
202
203      c = _rl_arg_getchar ();
204
205      if (c < 0)
206	{
207	  _rl_abort_internal ();
208	  return -1;
209	}
210
211      r = _rl_arg_dispatch (_rl_argcxt, c);
212      if (r <= 0 || (RL_ISSTATE (RL_STATE_NUMERICARG) == 0))
213        break;
214    }
215}
216
217/* Create a default argument. */
218void
219_rl_reset_argument ()
220{
221  rl_numeric_arg = rl_arg_sign = 1;
222  rl_explicit_arg = 0;
223  _rl_argcxt = 0;
224}
225
226/* Start a numeric argument with initial value KEY */
227int
228rl_digit_argument (ignore, key)
229     int ignore, key;
230{
231  _rl_arg_init ();
232  if (RL_ISSTATE (RL_STATE_CALLBACK))
233    {
234      _rl_arg_dispatch (_rl_argcxt, key);
235      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
236      return 0;
237    }
238  else
239    {
240      rl_execute_next (key);
241      return (rl_digit_loop ());
242    }
243}
244
245/* C-u, universal argument.  Multiply the current argument by 4.
246   Read a key.  If the key has nothing to do with arguments, then
247   dispatch on it.  If the key is the abort character then abort. */
248int
249rl_universal_argument (count, key)
250     int count, key;
251{
252  _rl_arg_init ();
253  rl_numeric_arg *= 4;
254
255  return (RL_ISSTATE (RL_STATE_CALLBACK) ? 0 : rl_digit_loop ());
256}
257
258int
259_rl_arg_callback (cxt)
260     _rl_arg_cxt cxt;
261{
262  int c, r;
263
264  c = _rl_arg_getchar ();
265
266  if (_rl_argcxt & NUM_READONE)
267    {
268      _rl_argcxt &= ~NUM_READONE;
269      rl_restore_prompt ();
270      rl_clear_message ();
271      RL_UNSETSTATE(RL_STATE_NUMERICARG);
272      rl_execute_next (c);
273      return 0;
274    }
275
276  r = _rl_arg_dispatch (cxt, c);
277  return (r != 1);
278}
279
280/* What to do when you abort reading an argument. */
281int
282rl_discard_argument ()
283{
284  rl_ding ();
285  rl_clear_message ();
286  _rl_reset_argument ();
287
288  return 0;
289}
290
291/* **************************************************************** */
292/*								    */
293/*			History Utilities			    */
294/*								    */
295/* **************************************************************** */
296
297/* We already have a history library, and that is what we use to control
298   the history features of readline.  This is our local interface to
299   the history mechanism. */
300
301/* While we are editing the history, this is the saved
302   version of the original line. */
303HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
304
305/* Set the history pointer back to the last entry in the history. */
306void
307_rl_start_using_history ()
308{
309  using_history ();
310  if (_rl_saved_line_for_history)
311    _rl_free_history_entry (_rl_saved_line_for_history);
312
313  _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
314}
315
316/* Free the contents (and containing structure) of a HIST_ENTRY. */
317void
318_rl_free_history_entry (entry)
319     HIST_ENTRY *entry;
320{
321  if (entry == 0)
322    return;
323
324  FREE (entry->line);
325  FREE (entry->timestamp);
326
327  free (entry);
328}
329
330/* Perhaps put back the current line if it has changed. */
331int
332rl_maybe_replace_line ()
333{
334  HIST_ENTRY *temp;
335
336  temp = current_history ();
337  /* If the current line has changed, save the changes. */
338  if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list))
339    {
340      temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
341      free (temp->line);
342      FREE (temp->timestamp);
343      free (temp);
344    }
345  return 0;
346}
347
348/* Restore the _rl_saved_line_for_history if there is one. */
349int
350rl_maybe_unsave_line ()
351{
352  if (_rl_saved_line_for_history)
353    {
354      /* Can't call with `1' because rl_undo_list might point to an undo
355	 list from a history entry, as in rl_replace_from_history() below. */
356      rl_replace_line (_rl_saved_line_for_history->line, 0);
357      rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data;
358      _rl_free_history_entry (_rl_saved_line_for_history);
359      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
360      rl_point = rl_end;	/* rl_replace_line sets rl_end */
361    }
362  else
363    rl_ding ();
364  return 0;
365}
366
367/* Save the current line in _rl_saved_line_for_history. */
368int
369rl_maybe_save_line ()
370{
371  if (_rl_saved_line_for_history == 0)
372    {
373      _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
374      _rl_saved_line_for_history->line = savestring (rl_line_buffer);
375      _rl_saved_line_for_history->timestamp = (char *)NULL;
376      _rl_saved_line_for_history->data = (char *)rl_undo_list;
377    }
378
379  return 0;
380}
381
382int
383_rl_free_saved_history_line ()
384{
385  if (_rl_saved_line_for_history)
386    {
387      _rl_free_history_entry (_rl_saved_line_for_history);
388      _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
389    }
390  return 0;
391}
392
393static void
394_rl_history_set_point ()
395{
396  rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1)
397		? _rl_history_saved_point
398		: rl_end;
399  if (rl_point > rl_end)
400    rl_point = rl_end;
401
402#if defined (VI_MODE)
403  if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap)
404    rl_point = 0;
405#endif /* VI_MODE */
406
407  if (rl_editing_mode == emacs_mode)
408    rl_mark = (rl_point == rl_end ? 0 : rl_end);
409}
410
411void
412rl_replace_from_history (entry, flags)
413     HIST_ENTRY *entry;
414     int flags;			/* currently unused */
415{
416  /* Can't call with `1' because rl_undo_list might point to an undo list
417     from a history entry, just like we're setting up here. */
418  rl_replace_line (entry->line, 0);
419  rl_undo_list = (UNDO_LIST *)entry->data;
420  rl_point = rl_end;
421  rl_mark = 0;
422
423#if defined (VI_MODE)
424  if (rl_editing_mode == vi_mode)
425    {
426      rl_point = 0;
427      rl_mark = rl_end;
428    }
429#endif
430}
431
432/* **************************************************************** */
433/*								    */
434/*			History Commands			    */
435/*								    */
436/* **************************************************************** */
437
438/* Meta-< goes to the start of the history. */
439int
440rl_beginning_of_history (count, key)
441     int count, key;
442{
443  return (rl_get_previous_history (1 + where_history (), key));
444}
445
446/* Meta-> goes to the end of the history.  (The current line). */
447int
448rl_end_of_history (count, key)
449     int count, key;
450{
451  rl_maybe_replace_line ();
452  using_history ();
453  rl_maybe_unsave_line ();
454  return 0;
455}
456
457/* Move down to the next history line. */
458int
459rl_get_next_history (count, key)
460     int count, key;
461{
462  HIST_ENTRY *temp;
463
464  if (count < 0)
465    return (rl_get_previous_history (-count, key));
466
467  if (count == 0)
468    return 0;
469
470  rl_maybe_replace_line ();
471
472  /* either not saved by rl_newline or at end of line, so set appropriately. */
473  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
474    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
475
476  temp = (HIST_ENTRY *)NULL;
477  while (count)
478    {
479      temp = next_history ();
480      if (!temp)
481	break;
482      --count;
483    }
484
485  if (temp == 0)
486    rl_maybe_unsave_line ();
487  else
488    {
489      rl_replace_from_history (temp, 0);
490      _rl_history_set_point ();
491    }
492  return 0;
493}
494
495/* Get the previous item out of our interactive history, making it the current
496   line.  If there is no previous history, just ding. */
497int
498rl_get_previous_history (count, key)
499     int count, key;
500{
501  HIST_ENTRY *old_temp, *temp;
502
503  if (count < 0)
504    return (rl_get_next_history (-count, key));
505
506  if (count == 0)
507    return 0;
508
509  /* either not saved by rl_newline or at end of line, so set appropriately. */
510  if (_rl_history_saved_point == -1 && (rl_point || rl_end))
511    _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
512
513  /* If we don't have a line saved, then save this one. */
514  rl_maybe_save_line ();
515
516  /* If the current line has changed, save the changes. */
517  rl_maybe_replace_line ();
518
519  temp = old_temp = (HIST_ENTRY *)NULL;
520  while (count)
521    {
522      temp = previous_history ();
523      if (temp == 0)
524	break;
525
526      old_temp = temp;
527      --count;
528    }
529
530  /* If there was a large argument, and we moved back to the start of the
531     history, that is not an error.  So use the last value found. */
532  if (!temp && old_temp)
533    temp = old_temp;
534
535  if (temp == 0)
536    rl_ding ();
537  else
538    {
539      rl_replace_from_history (temp, 0);
540      _rl_history_set_point ();
541    }
542
543  return 0;
544}
545
546/* **************************************************************** */
547/*								    */
548/*			    Editing Modes			    */
549/*								    */
550/* **************************************************************** */
551/* How to toggle back and forth between editing modes. */
552int
553rl_vi_editing_mode (count, key)
554     int count, key;
555{
556#if defined (VI_MODE)
557  _rl_set_insert_mode (RL_IM_INSERT, 1);	/* vi mode ignores insert mode */
558  rl_editing_mode = vi_mode;
559  rl_vi_insertion_mode (1, key);
560#endif /* VI_MODE */
561
562  return 0;
563}
564
565int
566rl_emacs_editing_mode (count, key)
567     int count, key;
568{
569  rl_editing_mode = emacs_mode;
570  _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */
571  _rl_keymap = emacs_standard_keymap;
572  return 0;
573}
574
575/* Function for the rest of the library to use to set insert/overwrite mode. */
576void
577_rl_set_insert_mode (im, force)
578     int im, force;
579{
580#ifdef CURSOR_MODE
581  _rl_set_cursor (im, force);
582#endif
583
584  rl_insert_mode = im;
585}
586
587/* Toggle overwrite mode.  A positive explicit argument selects overwrite
588   mode.  A negative or zero explicit argument selects insert mode. */
589int
590rl_overwrite_mode (count, key)
591     int count, key;
592{
593  if (rl_explicit_arg == 0)
594    _rl_set_insert_mode (rl_insert_mode ^ 1, 0);
595  else if (count > 0)
596    _rl_set_insert_mode (RL_IM_OVERWRITE, 0);
597  else
598    _rl_set_insert_mode (RL_IM_INSERT, 0);
599
600  return 0;
601}
602