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-1335  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 
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));
rl_insert_text(string)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 	free (release->text);
rl_delete_text(from,to)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 *
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, *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. */
164 int
165 rl_do_undo ()
166 {
167   UNDO_LIST *release;
168   int waiting_for_begin, start, end;
_rl_fix_point(fix_mark_too)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
_rl_replace_text(text,start,end)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:
rl_replace_line(text,clear_undo)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 
233 int
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. */
rl_forward_byte(count,key)253 int
254 rl_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 (). */
262 int
263 rl_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. */
271 int
272 rl_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);
rl_forward_char(count,key)286       rl_end_undo_group ();
287     }
288   return 0;
289 }
290 
291 /* Revert the current line to its previous state. */
292 int
293 rl_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. */
312 int
313 rl_undo_command (count, key)
314      int count, key __attribute__((unused));
315 {
316   if (count < 0)
317     return 0;	/* Nothing to do. */
318 
rl_forward_char(count,key)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