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