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