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 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 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 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 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 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 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 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 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 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 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 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 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 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 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