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.
272 lines
6.8 KiB
C
272 lines
6.8 KiB
C
/* macro.c -- keyboard macros for readline. */
|
|
|
|
/* Copyright (C) 1994-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"
|
|
|
|
/* **************************************************************** */
|
|
/* */
|
|
/* Hacking Keyboard Macros */
|
|
/* */
|
|
/* **************************************************************** */
|
|
|
|
/* The currently executing macro string. If this is non-zero,
|
|
then it is a malloc ()'ed string where input is coming from. */
|
|
char *rl_executing_macro = (char *)NULL;
|
|
|
|
/* The offset in the above string to the next character to be read. */
|
|
static int executing_macro_index;
|
|
|
|
/* The current macro string being built. Characters get stuffed
|
|
in here by add_macro_char (). */
|
|
static char *current_macro = (char *)NULL;
|
|
|
|
/* The size of the buffer allocated to current_macro. */
|
|
static int current_macro_size;
|
|
|
|
/* The index at which characters are being added to current_macro. */
|
|
static int current_macro_index;
|
|
|
|
/* A structure used to save nested macro strings.
|
|
It is a linked list of string/index for each saved macro. */
|
|
struct saved_macro {
|
|
struct saved_macro *next;
|
|
char *string;
|
|
int sindex;
|
|
};
|
|
|
|
/* The list of saved macros. */
|
|
static struct saved_macro *macro_list = (struct saved_macro *)NULL;
|
|
|
|
/* Set up to read subsequent input from STRING.
|
|
STRING is free ()'ed when we are done with it. */
|
|
void
|
|
_rl_with_macro_input (string)
|
|
char *string;
|
|
{
|
|
_rl_push_executing_macro ();
|
|
rl_executing_macro = string;
|
|
executing_macro_index = 0;
|
|
RL_SETSTATE(RL_STATE_MACROINPUT);
|
|
}
|
|
|
|
/* Return the next character available from a macro, or 0 if
|
|
there are no macro characters. */
|
|
int
|
|
_rl_next_macro_key ()
|
|
{
|
|
int c;
|
|
|
|
if (rl_executing_macro == 0)
|
|
return (0);
|
|
|
|
if (rl_executing_macro[executing_macro_index] == 0)
|
|
{
|
|
_rl_pop_executing_macro ();
|
|
return (_rl_next_macro_key ());
|
|
}
|
|
|
|
#if defined (READLINE_CALLBACKS)
|
|
c = rl_executing_macro[executing_macro_index++];
|
|
if (RL_ISSTATE (RL_STATE_CALLBACK) && RL_ISSTATE (RL_STATE_READCMD|RL_STATE_MOREINPUT) && rl_executing_macro[executing_macro_index] == 0)
|
|
_rl_pop_executing_macro ();
|
|
return c;
|
|
#else
|
|
return (rl_executing_macro[executing_macro_index++]);
|
|
#endif
|
|
}
|
|
|
|
/* Save the currently executing macro on a stack of saved macros. */
|
|
void
|
|
_rl_push_executing_macro ()
|
|
{
|
|
struct saved_macro *saver;
|
|
|
|
saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro));
|
|
saver->next = macro_list;
|
|
saver->sindex = executing_macro_index;
|
|
saver->string = rl_executing_macro;
|
|
|
|
macro_list = saver;
|
|
}
|
|
|
|
/* Discard the current macro, replacing it with the one
|
|
on the top of the stack of saved macros. */
|
|
void
|
|
_rl_pop_executing_macro ()
|
|
{
|
|
struct saved_macro *macro;
|
|
|
|
FREE (rl_executing_macro);
|
|
rl_executing_macro = (char *)NULL;
|
|
executing_macro_index = 0;
|
|
|
|
if (macro_list)
|
|
{
|
|
macro = macro_list;
|
|
rl_executing_macro = macro_list->string;
|
|
executing_macro_index = macro_list->sindex;
|
|
macro_list = macro_list->next;
|
|
xfree (macro);
|
|
}
|
|
|
|
if (rl_executing_macro == 0)
|
|
RL_UNSETSTATE(RL_STATE_MACROINPUT);
|
|
}
|
|
|
|
/* Add a character to the macro being built. */
|
|
void
|
|
_rl_add_macro_char (c)
|
|
int c;
|
|
{
|
|
if (current_macro_index + 1 >= current_macro_size)
|
|
{
|
|
if (current_macro == 0)
|
|
current_macro = (char *)xmalloc (current_macro_size = 25);
|
|
else
|
|
current_macro = (char *)xrealloc (current_macro, current_macro_size += 25);
|
|
}
|
|
|
|
current_macro[current_macro_index++] = c;
|
|
current_macro[current_macro_index] = '\0';
|
|
}
|
|
|
|
void
|
|
_rl_kill_kbd_macro ()
|
|
{
|
|
if (current_macro)
|
|
{
|
|
xfree (current_macro);
|
|
current_macro = (char *) NULL;
|
|
}
|
|
current_macro_size = current_macro_index = 0;
|
|
|
|
FREE (rl_executing_macro);
|
|
rl_executing_macro = (char *) NULL;
|
|
executing_macro_index = 0;
|
|
|
|
RL_UNSETSTATE(RL_STATE_MACRODEF);
|
|
}
|
|
|
|
/* Begin defining a keyboard macro.
|
|
Keystrokes are recorded as they are executed.
|
|
End the definition with rl_end_kbd_macro ().
|
|
If a numeric argument was explicitly typed, then append this
|
|
definition to the end of the existing macro, and start by
|
|
re-executing the existing macro. */
|
|
int
|
|
rl_start_kbd_macro (ignore1, ignore2)
|
|
int ignore1, ignore2;
|
|
{
|
|
if (RL_ISSTATE (RL_STATE_MACRODEF))
|
|
{
|
|
_rl_abort_internal ();
|
|
return -1;
|
|
}
|
|
|
|
if (rl_explicit_arg)
|
|
{
|
|
if (current_macro)
|
|
_rl_with_macro_input (savestring (current_macro));
|
|
}
|
|
else
|
|
current_macro_index = 0;
|
|
|
|
RL_SETSTATE(RL_STATE_MACRODEF);
|
|
return 0;
|
|
}
|
|
|
|
/* Stop defining a keyboard macro.
|
|
A numeric argument says to execute the macro right now,
|
|
that many times, counting the definition as the first time. */
|
|
int
|
|
rl_end_kbd_macro (count, ignore)
|
|
int count, ignore;
|
|
{
|
|
if (RL_ISSTATE (RL_STATE_MACRODEF) == 0)
|
|
{
|
|
_rl_abort_internal ();
|
|
return -1;
|
|
}
|
|
|
|
current_macro_index -= rl_key_sequence_length - 1;
|
|
current_macro[current_macro_index] = '\0';
|
|
|
|
RL_UNSETSTATE(RL_STATE_MACRODEF);
|
|
|
|
return (rl_call_last_kbd_macro (--count, 0));
|
|
}
|
|
|
|
/* Execute the most recently defined keyboard macro.
|
|
COUNT says how many times to execute it. */
|
|
int
|
|
rl_call_last_kbd_macro (count, ignore)
|
|
int count, ignore;
|
|
{
|
|
if (current_macro == 0)
|
|
_rl_abort_internal ();
|
|
|
|
if (RL_ISSTATE (RL_STATE_MACRODEF))
|
|
{
|
|
rl_ding (); /* no recursive macros */
|
|
current_macro[--current_macro_index] = '\0'; /* erase this char */
|
|
return 0;
|
|
}
|
|
|
|
while (count--)
|
|
_rl_with_macro_input (savestring (current_macro));
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
rl_push_macro_input (macro)
|
|
char *macro;
|
|
{
|
|
_rl_with_macro_input (macro);
|
|
}
|