xref: /openbsd/gnu/lib/libreadline/misc.c (revision 9704b281)
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 
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 /* 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. */
68 int _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. */
77 static int
rl_digit_loop()78 rl_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. */
158 int
rl_digit_argument(ignore,key)159 rl_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. */
167 int
rl_discard_argument()168 rl_discard_argument ()
169 {
170   rl_ding ();
171   rl_clear_message ();
172   _rl_init_argument ();
173   return 0;
174 }
175 
176 /* Create a default argument. */
177 int
_rl_init_argument()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. */
188 int
rl_universal_argument(count,key)189 rl_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. */
208 HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
209 
210 /* Set the history pointer back to the last entry in the history. */
211 void
_rl_start_using_history()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. */
222 void
_rl_free_history_entry(entry)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. */
234 int
rl_maybe_replace_line()235 rl_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. */
251 int
rl_maybe_unsave_line()252 rl_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. */
268 int
rl_maybe_save_line()269 rl_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 
280 int
_rl_free_saved_history_line()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 
291 static void
_rl_history_set_point()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 
309 void
rl_replace_from_history(entry,flags)310 rl_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. */
335 int
rl_beginning_of_history(count,key)336 rl_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). */
343 int
rl_end_of_history(count,key)344 rl_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. */
354 int
rl_get_next_history(count,key)355 rl_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. */
393 int
rl_get_previous_history(count,key)394 rl_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. */
447 int
rl_vi_editing_mode(count,key)448 rl_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 
460 int
rl_emacs_editing_mode(count,key)461 rl_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. */
471 void
_rl_set_insert_mode(im,force)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. */
484 int
rl_overwrite_mode(count,key)485 rl_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