xref: /NextBSD/contrib/libreadline/misc.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
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 
56 static int rl_digit_loop PARAMS((void));
57 static void _rl_history_set_point PARAMS((void));
58 
59 /* Forward declarations used in this file */
60 void _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. */
64 int _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. */
70 int _rl_history_saved_point = -1;
71 
72 /* **************************************************************** */
73 /*								    */
74 /*			Numeric Arguments			    */
75 /*								    */
76 /* **************************************************************** */
77 
78 int
_rl_arg_overflow()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 
94 void
_rl_arg_init()95 _rl_arg_init ()
96 {
97   rl_save_prompt ();
98   _rl_argcxt = 0;
99   RL_SETSTATE(RL_STATE_NUMERICARG);
100 }
101 
102 int
_rl_arg_getchar()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. */
118 int
_rl_arg_dispatch(cxt,c)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. */
195 static int
rl_digit_loop()196 rl_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. */
222 void
_rl_reset_argument()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 */
231 int
rl_digit_argument(ignore,key)232 rl_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. */
252 int
rl_universal_argument(count,key)253 rl_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 
262 int
_rl_arg_callback(cxt)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. */
285 int
rl_discard_argument()286 rl_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. */
307 HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
308 
309 /* Set the history pointer back to the last entry in the history. */
310 void
_rl_start_using_history()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. */
321 void
_rl_free_history_entry(entry)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. */
335 int
rl_maybe_replace_line()336 rl_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. */
353 int
rl_maybe_unsave_line()354 rl_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. */
372 int
rl_maybe_save_line()373 rl_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 
386 int
_rl_free_saved_history_line()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 
397 static void
_rl_history_set_point()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 
415 void
rl_replace_from_history(entry,flags)416 rl_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. */
443 int
rl_beginning_of_history(count,key)444 rl_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). */
451 int
rl_end_of_history(count,key)452 rl_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. */
462 int
rl_get_next_history(count,key)463 rl_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. */
501 int
rl_get_previous_history(count,key)502 rl_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. */
556 int
rl_vi_editing_mode(count,key)557 rl_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 
569 int
rl_emacs_editing_mode(count,key)570 rl_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. */
580 void
_rl_set_insert_mode(im,force)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. */
593 int
rl_overwrite_mode(count,key)594 rl_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