mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-15 04:31:49 +08:00
5836a818ec
This reverts commitb558ff043d
. This reverts commit4a11f20659
. The initial import commit failed to retain local changes made to readline's configure.in (and the commit message erroneously stated that there were no local changes that needed to be reapplied). Also the import caused a couple of build errors and a scattering of testsuite regressions throughout many arches. It's probably better to start over with this import, hopefully more carefully next time.
332 lines
7.0 KiB
C
332 lines
7.0 KiB
C
/* readline.c -- a general facility for reading lines of input
|
|
with emacs style editing and completion. */
|
|
|
|
/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
|
|
|
|
This file is part of the GNU Readline Library (Readline), a library
|
|
for reading lines of text with interactive input and history editing.
|
|
|
|
Readline is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Readline is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Readline. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#define READLINE_LIBRARY
|
|
|
|
#if defined (HAVE_CONFIG_H)
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
|
|
#if defined (HAVE_UNISTD_H)
|
|
# include <unistd.h> /* for _POSIX_VERSION */
|
|
#endif /* HAVE_UNISTD_H */
|
|
|
|
#if defined (HAVE_STDLIB_H)
|
|
# include <stdlib.h>
|
|
#else
|
|
# include "ansi_stdlib.h"
|
|
#endif /* HAVE_STDLIB_H */
|
|
|
|
#include <stdio.h>
|
|
|
|
/* System-specific feature definitions and include files. */
|
|
#include "rldefs.h"
|
|
|
|
/* Some standard library routines. */
|
|
#include "readline.h"
|
|
#include "history.h"
|
|
|
|
#include "rlprivate.h"
|
|
#include "xmalloc.h"
|
|
|
|
extern void replace_history_data PARAMS((int, histdata_t *, histdata_t *));
|
|
|
|
/* Non-zero tells rl_delete_text and rl_insert_text to not add to
|
|
the undo list. */
|
|
int _rl_doing_an_undo = 0;
|
|
|
|
/* How many unclosed undo groups we currently have. */
|
|
int _rl_undo_group_level = 0;
|
|
|
|
/* The current undo list for THE_LINE. */
|
|
UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
|
|
|
|
/* **************************************************************** */
|
|
/* */
|
|
/* Undo, and Undoing */
|
|
/* */
|
|
/* **************************************************************** */
|
|
|
|
static UNDO_LIST *
|
|
alloc_undo_entry (what, start, end, text)
|
|
enum undo_code what;
|
|
int start, end;
|
|
char *text;
|
|
{
|
|
UNDO_LIST *temp;
|
|
|
|
temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
|
|
temp->what = what;
|
|
temp->start = start;
|
|
temp->end = end;
|
|
temp->text = text;
|
|
|
|
temp->next = (UNDO_LIST *)NULL;
|
|
return temp;
|
|
}
|
|
|
|
/* Remember how to undo something. Concatenate some undos if that
|
|
seems right. */
|
|
void
|
|
rl_add_undo (what, start, end, text)
|
|
enum undo_code what;
|
|
int start, end;
|
|
char *text;
|
|
{
|
|
UNDO_LIST *temp;
|
|
|
|
temp = alloc_undo_entry (what, start, end, text);
|
|
temp->next = rl_undo_list;
|
|
rl_undo_list = temp;
|
|
}
|
|
|
|
/* Free the existing undo list. */
|
|
void
|
|
rl_free_undo_list ()
|
|
{
|
|
UNDO_LIST *release, *orig_list;
|
|
|
|
orig_list = rl_undo_list;
|
|
while (rl_undo_list)
|
|
{
|
|
release = rl_undo_list;
|
|
rl_undo_list = rl_undo_list->next;
|
|
|
|
if (release->what == UNDO_DELETE)
|
|
xfree (release->text);
|
|
|
|
xfree (release);
|
|
}
|
|
rl_undo_list = (UNDO_LIST *)NULL;
|
|
replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
|
|
}
|
|
|
|
UNDO_LIST *
|
|
_rl_copy_undo_entry (entry)
|
|
UNDO_LIST *entry;
|
|
{
|
|
UNDO_LIST *new;
|
|
|
|
new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
|
|
new->text = entry->text ? savestring (entry->text) : 0;
|
|
return new;
|
|
}
|
|
|
|
UNDO_LIST *
|
|
_rl_copy_undo_list (head)
|
|
UNDO_LIST *head;
|
|
{
|
|
UNDO_LIST *list, *new, *roving, *c;
|
|
|
|
if (head == 0)
|
|
return head;
|
|
|
|
list = head;
|
|
new = 0;
|
|
while (list)
|
|
{
|
|
c = _rl_copy_undo_entry (list);
|
|
if (new == 0)
|
|
roving = new = c;
|
|
else
|
|
{
|
|
roving->next = c;
|
|
roving = roving->next;
|
|
}
|
|
list = list->next;
|
|
}
|
|
|
|
roving->next = 0;
|
|
return new;
|
|
}
|
|
|
|
/* Undo the next thing in the list. Return 0 if there
|
|
is nothing to undo, or non-zero if there was. */
|
|
int
|
|
rl_do_undo ()
|
|
{
|
|
UNDO_LIST *release;
|
|
int waiting_for_begin, start, end;
|
|
|
|
#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
|
|
|
|
start = end = waiting_for_begin = 0;
|
|
do
|
|
{
|
|
if (rl_undo_list == 0)
|
|
return (0);
|
|
|
|
_rl_doing_an_undo = 1;
|
|
RL_SETSTATE(RL_STATE_UNDOING);
|
|
|
|
/* To better support vi-mode, a start or end value of -1 means
|
|
rl_point, and a value of -2 means rl_end. */
|
|
if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
|
|
{
|
|
start = TRANS (rl_undo_list->start);
|
|
end = TRANS (rl_undo_list->end);
|
|
}
|
|
|
|
switch (rl_undo_list->what)
|
|
{
|
|
/* Undoing deletes means inserting some text. */
|
|
case UNDO_DELETE:
|
|
rl_point = start;
|
|
rl_insert_text (rl_undo_list->text);
|
|
xfree (rl_undo_list->text);
|
|
break;
|
|
|
|
/* Undoing inserts means deleting some text. */
|
|
case UNDO_INSERT:
|
|
rl_delete_text (start, end);
|
|
rl_point = start;
|
|
break;
|
|
|
|
/* Undoing an END means undoing everything 'til we get to a BEGIN. */
|
|
case UNDO_END:
|
|
waiting_for_begin++;
|
|
break;
|
|
|
|
/* Undoing a BEGIN means that we are done with this group. */
|
|
case UNDO_BEGIN:
|
|
if (waiting_for_begin)
|
|
waiting_for_begin--;
|
|
else
|
|
rl_ding ();
|
|
break;
|
|
}
|
|
|
|
_rl_doing_an_undo = 0;
|
|
RL_UNSETSTATE(RL_STATE_UNDOING);
|
|
|
|
release = rl_undo_list;
|
|
rl_undo_list = rl_undo_list->next;
|
|
replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
|
|
|
|
xfree (release);
|
|
}
|
|
while (waiting_for_begin);
|
|
|
|
return (1);
|
|
}
|
|
#undef TRANS
|
|
|
|
int
|
|
_rl_fix_last_undo_of_type (type, start, end)
|
|
int type, start, end;
|
|
{
|
|
UNDO_LIST *rl;
|
|
|
|
for (rl = rl_undo_list; rl; rl = rl->next)
|
|
{
|
|
if (rl->what == type)
|
|
{
|
|
rl->start = start;
|
|
rl->end = end;
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* Begin a group. Subsequent undos are undone as an atomic operation. */
|
|
int
|
|
rl_begin_undo_group ()
|
|
{
|
|
rl_add_undo (UNDO_BEGIN, 0, 0, 0);
|
|
_rl_undo_group_level++;
|
|
return 0;
|
|
}
|
|
|
|
/* End an undo group started with rl_begin_undo_group (). */
|
|
int
|
|
rl_end_undo_group ()
|
|
{
|
|
rl_add_undo (UNDO_END, 0, 0, 0);
|
|
_rl_undo_group_level--;
|
|
return 0;
|
|
}
|
|
|
|
/* Save an undo entry for the text from START to END. */
|
|
int
|
|
rl_modifying (start, end)
|
|
int start, end;
|
|
{
|
|
if (start > end)
|
|
{
|
|
SWAP (start, end);
|
|
}
|
|
|
|
if (start != end)
|
|
{
|
|
char *temp = rl_copy_text (start, end);
|
|
rl_begin_undo_group ();
|
|
rl_add_undo (UNDO_DELETE, start, end, temp);
|
|
rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
|
|
rl_end_undo_group ();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Revert the current line to its previous state. */
|
|
int
|
|
rl_revert_line (count, key)
|
|
int count, key;
|
|
{
|
|
if (rl_undo_list == 0)
|
|
rl_ding ();
|
|
else
|
|
{
|
|
while (rl_undo_list)
|
|
rl_do_undo ();
|
|
#if defined (VI_MODE)
|
|
if (rl_editing_mode == vi_mode)
|
|
rl_point = rl_mark = 0; /* rl_end should be set correctly */
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Do some undoing of things that were done. */
|
|
int
|
|
rl_undo_command (count, key)
|
|
int count, key;
|
|
{
|
|
if (count < 0)
|
|
return 0; /* Nothing to do. */
|
|
|
|
while (count)
|
|
{
|
|
if (rl_do_undo ())
|
|
count--;
|
|
else
|
|
{
|
|
rl_ding ();
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|