1 /* readline.c -- a general facility for reading lines of input 2 with emacs style editing and completion. */ 3 4 /* Copyright (C) 1987-2009 Free Software Foundation, Inc. 5 6 This file is part of the GNU Readline Library (Readline), a library 7 for reading lines of text with interactive input and history editing. 8 9 Readline is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Readline is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Readline. If not, see <http://www.gnu.org/licenses/>. 21 */ 22 23 #define READLINE_LIBRARY 24 25 #if defined (HAVE_CONFIG_H) 26 # include <config.h> 27 #endif 28 29 #include <sys/types.h> 30 31 #if defined (HAVE_UNISTD_H) 32 # include <unistd.h> /* for _POSIX_VERSION */ 33 #endif /* HAVE_UNISTD_H */ 34 35 #if defined (HAVE_STDLIB_H) 36 # include <stdlib.h> 37 #else 38 # include "ansi_stdlib.h" 39 #endif /* HAVE_STDLIB_H */ 40 41 #include <stdio.h> 42 43 /* System-specific feature definitions and include files. */ 44 #include "rldefs.h" 45 46 /* Some standard library routines. */ 47 #include "readline.h" 48 #include "history.h" 49 50 #include "rlprivate.h" 51 #include "xmalloc.h" 52 53 extern void replace_history_data PARAMS((int, histdata_t *, histdata_t *)); 54 55 /* Non-zero tells rl_delete_text and rl_insert_text to not add to 56 the undo list. */ 57 int _rl_doing_an_undo = 0; 58 59 /* How many unclosed undo groups we currently have. */ 60 int _rl_undo_group_level = 0; 61 62 /* The current undo list for THE_LINE. */ 63 UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; 64 65 /* **************************************************************** */ 66 /* */ 67 /* Undo, and Undoing */ 68 /* */ 69 /* **************************************************************** */ 70 71 static UNDO_LIST * 72 alloc_undo_entry (what, start, end, text) 73 enum undo_code what; 74 int start, end; 75 char *text; 76 { 77 UNDO_LIST *temp; 78 79 temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); 80 temp->what = what; 81 temp->start = start; 82 temp->end = end; 83 temp->text = text; 84 85 temp->next = (UNDO_LIST *)NULL; 86 return temp; 87 } 88 89 /* Remember how to undo something. Concatenate some undos if that 90 seems right. */ 91 void 92 rl_add_undo (what, start, end, text) 93 enum undo_code what; 94 int start, end; 95 char *text; 96 { 97 UNDO_LIST *temp; 98 99 temp = alloc_undo_entry (what, start, end, text); 100 temp->next = rl_undo_list; 101 rl_undo_list = temp; 102 } 103 104 /* Free the existing undo list. */ 105 void 106 rl_free_undo_list () 107 { 108 UNDO_LIST *release, *orig_list; 109 110 orig_list = rl_undo_list; 111 while (rl_undo_list) 112 { 113 release = rl_undo_list; 114 rl_undo_list = rl_undo_list->next; 115 116 if (release->what == UNDO_DELETE) 117 xfree (release->text); 118 119 xfree (release); 120 } 121 rl_undo_list = (UNDO_LIST *)NULL; 122 replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL); 123 } 124 125 UNDO_LIST * 126 _rl_copy_undo_entry (entry) 127 UNDO_LIST *entry; 128 { 129 UNDO_LIST *new; 130 131 new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL); 132 new->text = entry->text ? savestring (entry->text) : 0; 133 return new; 134 } 135 136 UNDO_LIST * 137 _rl_copy_undo_list (head) 138 UNDO_LIST *head; 139 { 140 UNDO_LIST *list, *new, *roving, *c; 141 142 if (head == 0) 143 return head; 144 145 list = head; 146 new = 0; 147 while (list) 148 { 149 c = _rl_copy_undo_entry (list); 150 if (new == 0) 151 roving = new = c; 152 else 153 { 154 roving->next = c; 155 roving = roving->next; 156 } 157 list = list->next; 158 } 159 160 roving->next = 0; 161 return new; 162 } 163 164 /* Undo the next thing in the list. Return 0 if there 165 is nothing to undo, or non-zero if there was. */ 166 int 167 rl_do_undo () 168 { 169 UNDO_LIST *release; 170 int waiting_for_begin, start, end; 171 172 #define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i))) 173 174 start = end = waiting_for_begin = 0; 175 do 176 { 177 if (rl_undo_list == 0) 178 return (0); 179 180 _rl_doing_an_undo = 1; 181 RL_SETSTATE(RL_STATE_UNDOING); 182 183 /* To better support vi-mode, a start or end value of -1 means 184 rl_point, and a value of -2 means rl_end. */ 185 if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT) 186 { 187 start = TRANS (rl_undo_list->start); 188 end = TRANS (rl_undo_list->end); 189 } 190 191 switch (rl_undo_list->what) 192 { 193 /* Undoing deletes means inserting some text. */ 194 case UNDO_DELETE: 195 rl_point = start; 196 rl_insert_text (rl_undo_list->text); 197 xfree (rl_undo_list->text); 198 break; 199 200 /* Undoing inserts means deleting some text. */ 201 case UNDO_INSERT: 202 rl_delete_text (start, end); 203 rl_point = start; 204 break; 205 206 /* Undoing an END means undoing everything 'til we get to a BEGIN. */ 207 case UNDO_END: 208 waiting_for_begin++; 209 break; 210 211 /* Undoing a BEGIN means that we are done with this group. */ 212 case UNDO_BEGIN: 213 if (waiting_for_begin) 214 waiting_for_begin--; 215 else 216 rl_ding (); 217 break; 218 } 219 220 _rl_doing_an_undo = 0; 221 RL_UNSETSTATE(RL_STATE_UNDOING); 222 223 release = rl_undo_list; 224 rl_undo_list = rl_undo_list->next; 225 replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list); 226 227 xfree (release); 228 } 229 while (waiting_for_begin); 230 231 return (1); 232 } 233 #undef TRANS 234 235 int 236 _rl_fix_last_undo_of_type (type, start, end) 237 int type, start, end; 238 { 239 UNDO_LIST *rl; 240 241 for (rl = rl_undo_list; rl; rl = rl->next) 242 { 243 if (rl->what == type) 244 { 245 rl->start = start; 246 rl->end = end; 247 return 0; 248 } 249 } 250 return 1; 251 } 252 253 /* Begin a group. Subsequent undos are undone as an atomic operation. */ 254 int 255 rl_begin_undo_group () 256 { 257 rl_add_undo (UNDO_BEGIN, 0, 0, 0); 258 _rl_undo_group_level++; 259 return 0; 260 } 261 262 /* End an undo group started with rl_begin_undo_group (). */ 263 int 264 rl_end_undo_group () 265 { 266 rl_add_undo (UNDO_END, 0, 0, 0); 267 _rl_undo_group_level--; 268 return 0; 269 } 270 271 /* Save an undo entry for the text from START to END. */ 272 int 273 rl_modifying (start, end) 274 int start, end; 275 { 276 if (start > end) 277 { 278 SWAP (start, end); 279 } 280 281 if (start != end) 282 { 283 char *temp = rl_copy_text (start, end); 284 rl_begin_undo_group (); 285 rl_add_undo (UNDO_DELETE, start, end, temp); 286 rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); 287 rl_end_undo_group (); 288 } 289 return 0; 290 } 291 292 /* Revert the current line to its previous state. */ 293 int 294 rl_revert_line (count, key) 295 int count, key; 296 { 297 if (rl_undo_list == 0) 298 rl_ding (); 299 else 300 { 301 while (rl_undo_list) 302 rl_do_undo (); 303 #if defined (VI_MODE) 304 if (rl_editing_mode == vi_mode) 305 rl_point = rl_mark = 0; /* rl_end should be set correctly */ 306 #endif 307 } 308 309 return 0; 310 } 311 312 /* Do some undoing of things that were done. */ 313 int 314 rl_undo_command (count, key) 315 int count, key; 316 { 317 if (count < 0) 318 return 0; /* Nothing to do. */ 319 320 while (count) 321 { 322 if (rl_do_undo ()) 323 count--; 324 else 325 { 326 rl_ding (); 327 break; 328 } 329 } 330 return 0; 331 } 332