]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/misc.c
ab1e1337fd3ab88b1a8a5094fe96d65e7d1d3aad
[thirdparty/bash.git] / lib / readline / misc.c
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
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
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
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
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
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
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
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
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
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
252 rl_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. */
270 int
271 rl_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
289 int
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
300 static 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
318 void
319 rl_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. */
346 int
347 rl_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). */
354 int
355 rl_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. */
365 int
366 rl_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. */
404 int
405 rl_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. */
459 int
460 rl_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
472 int
473 rl_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. */
483 void
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. */
496 int
497 rl_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 }