1 /* readline.c -- a general facility for reading lines of input
2 with emacs style editing and completion. */
3
4 /* Copyright (C) 1987, 1989, 1992, 2006 Free Software Foundation, Inc.
5
6 This file is part of the GNU Readline Library, a library for
7 reading lines of text with interactive input and history editing.
8
9 The GNU Readline Library is free software; you can redistribute it
10 and/or modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2, or
12 (at your option) any later version.
13
14 The GNU Readline Library is distributed in the hope that it will be
15 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 The GNU General Public License is often shipped with GNU software, and
20 is generally kept in a file called COPYING or LICENSE. If you do not
21 have a copy of the license, write to the Free Software Foundation,
22 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
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 *
alloc_undo_entry(what,start,end,text)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
rl_add_undo(what,start,end,text)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
rl_free_undo_list()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 free (release->text);
118
119 free (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 *
_rl_copy_undo_entry(entry)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 *
_rl_copy_undo_list(head)137 _rl_copy_undo_list (head)
138 UNDO_LIST *head;
139 {
140 UNDO_LIST *list, *new, *roving, *c;
141
142 list = head;
143 new = 0;
144 while (list)
145 {
146 c = _rl_copy_undo_entry (list);
147 if (new == 0)
148 roving = new = c;
149 else
150 {
151 roving->next = c;
152 roving = roving->next;
153 }
154 list = list->next;
155 }
156
157 roving->next = 0;
158 return new;
159 }
160
161 /* Undo the next thing in the list. Return 0 if there
162 is nothing to undo, or non-zero if there was. */
163 int
rl_do_undo()164 rl_do_undo ()
165 {
166 UNDO_LIST *release;
167 int waiting_for_begin, start, end;
168
169 #define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
170
171 start = end = waiting_for_begin = 0;
172 do
173 {
174 if (!rl_undo_list)
175 return (0);
176
177 _rl_doing_an_undo = 1;
178 RL_SETSTATE(RL_STATE_UNDOING);
179
180 /* To better support vi-mode, a start or end value of -1 means
181 rl_point, and a value of -2 means rl_end. */
182 if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
183 {
184 start = TRANS (rl_undo_list->start);
185 end = TRANS (rl_undo_list->end);
186 }
187
188 switch (rl_undo_list->what)
189 {
190 /* Undoing deletes means inserting some text. */
191 case UNDO_DELETE:
192 rl_point = start;
193 rl_insert_text (rl_undo_list->text);
194 free (rl_undo_list->text);
195 break;
196
197 /* Undoing inserts means deleting some text. */
198 case UNDO_INSERT:
199 rl_delete_text (start, end);
200 rl_point = start;
201 break;
202
203 /* Undoing an END means undoing everything 'til we get to a BEGIN. */
204 case UNDO_END:
205 waiting_for_begin++;
206 break;
207
208 /* Undoing a BEGIN means that we are done with this group. */
209 case UNDO_BEGIN:
210 if (waiting_for_begin)
211 waiting_for_begin--;
212 else
213 rl_ding ();
214 break;
215 }
216
217 _rl_doing_an_undo = 0;
218 RL_UNSETSTATE(RL_STATE_UNDOING);
219
220 release = rl_undo_list;
221 rl_undo_list = rl_undo_list->next;
222 replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
223
224 free (release);
225 }
226 while (waiting_for_begin);
227
228 return (1);
229 }
230 #undef TRANS
231
232 int
_rl_fix_last_undo_of_type(type,start,end)233 _rl_fix_last_undo_of_type (type, start, end)
234 int type, start, end;
235 {
236 UNDO_LIST *rl;
237
238 for (rl = rl_undo_list; rl; rl = rl->next)
239 {
240 if (rl->what == type)
241 {
242 rl->start = start;
243 rl->end = end;
244 return 0;
245 }
246 }
247 return 1;
248 }
249
250 /* Begin a group. Subsequent undos are undone as an atomic operation. */
251 int
rl_begin_undo_group()252 rl_begin_undo_group ()
253 {
254 rl_add_undo (UNDO_BEGIN, 0, 0, 0);
255 _rl_undo_group_level++;
256 return 0;
257 }
258
259 /* End an undo group started with rl_begin_undo_group (). */
260 int
rl_end_undo_group()261 rl_end_undo_group ()
262 {
263 rl_add_undo (UNDO_END, 0, 0, 0);
264 _rl_undo_group_level--;
265 return 0;
266 }
267
268 /* Save an undo entry for the text from START to END. */
269 int
rl_modifying(start,end)270 rl_modifying (start, end)
271 int start, end;
272 {
273 if (start > end)
274 {
275 SWAP (start, end);
276 }
277
278 if (start != end)
279 {
280 char *temp = rl_copy_text (start, end);
281 rl_begin_undo_group ();
282 rl_add_undo (UNDO_DELETE, start, end, temp);
283 rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
284 rl_end_undo_group ();
285 }
286 return 0;
287 }
288
289 /* Revert the current line to its previous state. */
290 int
rl_revert_line(count,key)291 rl_revert_line (count, key)
292 int count, key;
293 {
294 if (!rl_undo_list)
295 rl_ding ();
296 else
297 {
298 while (rl_undo_list)
299 rl_do_undo ();
300 #if defined (VI_MODE)
301 if (rl_editing_mode == vi_mode)
302 rl_point = rl_mark = 0; /* rl_end should be set correctly */
303 #endif
304 }
305
306 return 0;
307 }
308
309 /* Do some undoing of things that were done. */
310 int
rl_undo_command(count,key)311 rl_undo_command (count, key)
312 int count, key;
313 {
314 if (count < 0)
315 return 0; /* Nothing to do. */
316
317 while (count)
318 {
319 if (rl_do_undo ())
320 count--;
321 else
322 {
323 rl_ding ();
324 break;
325 }
326 }
327 return 0;
328 }
329