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 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23#define READLINE_LIBRARY
24
25#if defined (HAVE_CONFIG_H)
26# include "config_readline.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
53extern 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. */
57int _rl_doing_an_undo = 0;
58
59/* How many unclosed undo groups we currently have. */
60int _rl_undo_group_level = 0;
61
62/* The current undo list for THE_LINE. */
63UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
64
65/* **************************************************************** */
66/* */
67/* Undo, and Undoing */
68/* */
69/* **************************************************************** */
70
71static UNDO_LIST *
72alloc_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. */
91void
92rl_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. */
105void
106rl_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
125UNDO_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
136UNDO_LIST *
137_rl_copy_undo_list (head)
138 UNDO_LIST *head;
139{
140 UNDO_LIST *list, *new, *c;
141 UNDO_LIST *roving= NULL;
142
143 list = head;
144 new = 0;
145 while (list)
146 {
147 c = _rl_copy_undo_entry (list);
148 if (new == 0)
149 roving = new = c;
150 else
151 {
152 roving->next = c;
153 roving = roving->next;
154 }
155 list = list->next;
156 }
157
158 roving->next = 0;
159 return new;
160}
161
162/* Undo the next thing in the list. Return 0 if there
163 is nothing to undo, or non-zero if there was. */
164int
165rl_do_undo ()
166{
167 UNDO_LIST *release;
168 int waiting_for_begin, start, end;
169
170#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
171
172 start = end = waiting_for_begin = 0;
173 do
174 {
175 if (!rl_undo_list)
176 return (0);
177
178 _rl_doing_an_undo = 1;
179 RL_SETSTATE(RL_STATE_UNDOING);
180
181 /* To better support vi-mode, a start or end value of -1 means
182 rl_point, and a value of -2 means rl_end. */
183 if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
184 {
185 start = TRANS (rl_undo_list->start);
186 end = TRANS (rl_undo_list->end);
187 }
188
189 switch (rl_undo_list->what)
190 {
191 /* Undoing deletes means inserting some text. */
192 case UNDO_DELETE:
193 rl_point = start;
194 rl_insert_text (rl_undo_list->text);
195 free (rl_undo_list->text);
196 break;
197
198 /* Undoing inserts means deleting some text. */
199 case UNDO_INSERT:
200 rl_delete_text (start, end);
201 rl_point = start;
202 break;
203
204 /* Undoing an END means undoing everything 'til we get to a BEGIN. */
205 case UNDO_END:
206 waiting_for_begin++;
207 break;
208
209 /* Undoing a BEGIN means that we are done with this group. */
210 case UNDO_BEGIN:
211 if (waiting_for_begin)
212 waiting_for_begin--;
213 else
214 rl_ding ();
215 break;
216 }
217
218 _rl_doing_an_undo = 0;
219 RL_UNSETSTATE(RL_STATE_UNDOING);
220
221 release = rl_undo_list;
222 rl_undo_list = rl_undo_list->next;
223 replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
224
225 free (release);
226 }
227 while (waiting_for_begin);
228
229 return (1);
230}
231#undef TRANS
232
233int
234_rl_fix_last_undo_of_type (type, start, end)
235 enum undo_code type;
236 int start, end;
237{
238 UNDO_LIST *rl;
239
240 for (rl = rl_undo_list; rl; rl = rl->next)
241 {
242 if (rl->what == type)
243 {
244 rl->start = start;
245 rl->end = end;
246 return 0;
247 }
248 }
249 return 1;
250}
251
252/* Begin a group. Subsequent undos are undone as an atomic operation. */
253int
254rl_begin_undo_group ()
255{
256 rl_add_undo (UNDO_BEGIN, 0, 0, 0);
257 _rl_undo_group_level++;
258 return 0;
259}
260
261/* End an undo group started with rl_begin_undo_group (). */
262int
263rl_end_undo_group ()
264{
265 rl_add_undo (UNDO_END, 0, 0, 0);
266 _rl_undo_group_level--;
267 return 0;
268}
269
270/* Save an undo entry for the text from START to END. */
271int
272rl_modifying (start, end)
273 int start, end;
274{
275 if (start > end)
276 {
277 SWAP (start, end);
278 }
279
280 if (start != end)
281 {
282 char *temp = rl_copy_text (start, end);
283 rl_begin_undo_group ();
284 rl_add_undo (UNDO_DELETE, start, end, temp);
285 rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
286 rl_end_undo_group ();
287 }
288 return 0;
289}
290
291/* Revert the current line to its previous state. */
292int
293rl_revert_line (count, key)
294 int count __attribute__((unused)), key __attribute__((unused));
295{
296 if (!rl_undo_list)
297 rl_ding ();
298 else
299 {
300 while (rl_undo_list)
301 rl_do_undo ();
302#if defined (VI_MODE)
303 if (rl_editing_mode == vi_mode)
304 rl_point = rl_mark = 0; /* rl_end should be set correctly */
305#endif
306 }
307
308 return 0;
309}
310
311/* Do some undoing of things that were done. */
312int
313rl_undo_command (count, key)
314 int count, key __attribute__((unused));
315{
316 if (count < 0)
317 return 0; /* Nothing to do. */
318
319 while (count)
320 {
321 if (rl_do_undo ())
322 count--;
323 else
324 {
325 rl_ding ();
326 break;
327 }
328 }
329 return 0;
330}
331