aboutsummaryrefslogtreecommitdiff
path: root/gnu/lib/libreadline/history.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/lib/libreadline/history.c')
-rw-r--r--gnu/lib/libreadline/history.c477
1 files changed, 331 insertions, 146 deletions
diff --git a/gnu/lib/libreadline/history.c b/gnu/lib/libreadline/history.c
index 115a8af20651..45c6c780d335 100644
--- a/gnu/lib/libreadline/history.c
+++ b/gnu/lib/libreadline/history.c
@@ -1,48 +1,79 @@
/* History.c -- standalone history library */
-/* Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
This file contains the GNU History Library (the Library), a set of
routines for managing the text of previously typed lines.
The Library 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 2 of the License, or
- (at your option) any later version.
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
- The Library 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.
+ The Library 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 this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
/* The goal is to make the implementation transparent, so that you
don't have to know what data types are used, just what functions
you can call. I think I have done that. */
-/* Remove these declarations when we have a complete libgnu.a. */
-#if !defined (STATIC_MALLOC)
-extern char *xmalloc (), *xrealloc ();
-#else
+#if defined (STATIC_MALLOC)
static char *xmalloc (), *xrealloc ();
-#endif
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* STATIC_MALLOC */
-#include "sysdep.h"
#include <stdio.h>
-#include <errno.h>
-#ifndef NO_SYS_FILE
+#include <sys/types.h>
#include <sys/file.h>
-#endif
#include <sys/stat.h>
#include <fcntl.h>
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+#include <errno.h>
+
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#if defined (__GNUC__)
+# undef alloca
+# define alloca __builtin_alloca
+#else
+# if defined (sparc) || defined (HAVE_ALLOCA_H)
+# include <alloca.h>
+# else
+extern char *alloca ();
+# endif /* sparc || HAVE_ALLOCA_H */
+#endif /* !__GNU_C__ */
#include "history.h"
#ifndef savestring
-#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
+extern char *xmalloc ();
+# ifndef strcpy
+extern char *strcpy ();
+# endif
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
#endif
#ifndef whitespace
@@ -54,9 +85,16 @@ static char *xmalloc (), *xrealloc ();
#endif
#ifndef member
-#define member(c, s) ((c) ? index ((s), (c)) : 0)
+# ifndef strchr
+extern char *strchr ();
+# endif
+#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0)
#endif
+static char error_pointer;
+
+static char *get_history_word_specifier ();
+
/* **************************************************************** */
/* */
/* History Functions */
@@ -108,6 +146,32 @@ char *history_no_expand_chars = " \t\n\r=";
/* The logical `base' of the history array. It defaults to 1. */
int history_base = 1;
+/* Return the current HISTORY_STATE of the history. */
+HISTORY_STATE *
+history_get_history_state ()
+{
+ HISTORY_STATE *state;
+
+ state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
+ state->entries = the_history;
+ state->offset = history_offset;
+ state->length = history_length;
+ state->size = history_size;
+
+ return (state);
+}
+
+/* Set the state of the current history array to STATE. */
+void
+history_set_history_state (state)
+ HISTORY_STATE *state;
+{
+ the_history = state->entries;
+ history_offset = state->offset;
+ history_length = state->length;
+ history_size = state->size;
+}
+
/* Begin a session in which the history functions might be used. This
initializes interactive variables. */
void
@@ -179,7 +243,7 @@ add_history (string)
xrealloc (the_history,
((history_size += DEFAULT_HISTORY_GROW_SIZE)
* sizeof (HIST_ENTRY *)));
- }
+ }
history_length++;
}
}
@@ -372,6 +436,7 @@ stifle_history (max)
{
if (max < 0)
max = 0;
+
if (history_length > max)
{
register int i, j;
@@ -382,12 +447,14 @@ stifle_history (max)
free (the_history[i]->line);
free (the_history[i]);
}
+
history_base = i;
for (j = 0, i = history_length - max; j < max; i++, j++)
the_history[j] = the_history[i];
the_history[j] = (HIST_ENTRY *)NULL;
history_length = j;
}
+
history_stifled = 1;
max_input_history = max;
}
@@ -399,11 +466,13 @@ int
unstifle_history ()
{
int result = max_input_history;
+
if (history_stifled)
{
- result = - result;
+ result = -result;
history_stifled = 0;
}
+
return (result);
}
@@ -418,11 +487,18 @@ history_filename (filename)
if (!return_val)
{
- char *home = (char *)getenv ("HOME");
- if (!home) home = ".";
+ char *home;
+
+ home = getenv ("HOME");
+
+ if (!home)
+ home = ".";
+
return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history"));
+
sprintf (return_val, "%s/.history", home);
}
+
return (return_val);
}
@@ -450,7 +526,6 @@ read_history_range (filename, from, to)
char *input, *buffer = (char *)NULL;
int file, current_line;
struct stat finfo;
- extern int errno;
input = history_filename (filename);
file = open (input, O_RDONLY, 0666);
@@ -459,7 +534,7 @@ read_history_range (filename, from, to)
(stat (input, &finfo) == -1))
goto error_and_exit;
- buffer = (char *)xmalloc (finfo.st_size + 1);
+ buffer = (char *)xmalloc ((int)finfo.st_size + 1);
if (read (file, buffer, finfo.st_size) != finfo.st_size)
error_and_exit:
@@ -467,6 +542,9 @@ read_history_range (filename, from, to)
if (file >= 0)
close (file);
+ if (input)
+ free (input);
+
if (buffer)
free (buffer);
@@ -511,17 +589,25 @@ read_history_range (filename, from, to)
line_start = line_end + 1;
}
+
+ if (input)
+ free (input);
+
+ if (buffer)
+ free (buffer);
+
return (0);
}
/* Truncate the history file FNAME, leaving only LINES trailing lines.
If FNAME is NULL, then use ~/.history. */
+int
history_truncate_file (fname, lines)
char *fname;
register int lines;
{
register int i;
- int file;
+ int file, chars_read;
char *buffer = (char *)NULL, *filename;
struct stat finfo;
@@ -534,13 +620,16 @@ history_truncate_file (fname, lines)
if (file == -1)
goto truncate_exit;
- buffer = (char *)xmalloc (finfo.st_size + 1);
- read (file, buffer, finfo.st_size);
+ buffer = (char *)xmalloc ((int)finfo.st_size + 1);
+ chars_read = read (file, buffer, finfo.st_size);
close (file);
+ if (chars_read <= 0)
+ goto truncate_exit;
+
/* Count backwards from the end of buffer until we have passed
LINES lines. */
- for (i = finfo.st_size; lines && i; i--)
+ for (i = chars_read - 1; lines && i; i--)
{
if (buffer[i] == '\n')
lines--;
@@ -572,6 +661,7 @@ history_truncate_file (fname, lines)
free (buffer);
free (filename);
+ return 0;
}
#define HISTORY_APPEND 0
@@ -585,8 +675,7 @@ history_do_write (filename, nelements, overwrite)
char *filename;
int nelements, overwrite;
{
- extern int errno;
- register int i, j;
+ register int i;
char *output = history_filename (filename);
int file, mode;
@@ -596,7 +685,12 @@ history_do_write (filename, nelements, overwrite)
mode = O_WRONLY | O_APPEND;
if ((file = open (output, mode, 0666)) == -1)
- return (errno);
+ {
+ if (output)
+ free (output);
+
+ return (errno);
+ }
if (nelements > history_length)
nelements = history_length;
@@ -627,9 +721,13 @@ history_do_write (filename, nelements, overwrite)
}
close (file);
+
+ if (output)
+ free (output);
+
return (0);
}
-
+
/* Append NELEMENT entries to FILENAME. The entries appended are from
the end of the list minus NELEMENTs up to the end of the list. */
int
@@ -700,13 +798,13 @@ HIST_ENTRY *
history_get (offset)
int offset;
{
- int index = offset - history_base;
+ int local_index = offset - history_base;
- if (index >= history_length ||
- index < 0 ||
+ if (local_index >= history_length ||
+ local_index < 0 ||
!the_history)
return ((HIST_ENTRY *)NULL);
- return (the_history[index]);
+ return (the_history[local_index]);
}
/* Search for STRING in the history list. DIR is < 0 for searching
@@ -801,7 +899,6 @@ get_history_event (string, caller_index, delimiting_quote)
}
/* Hack case of numeric line specification. */
- read_which:
if (string[i] == '-')
{
sign = -1;
@@ -834,7 +931,7 @@ get_history_event (string, caller_index, delimiting_quote)
a '?', then the string may be anywhere on the line. Otherwise,
the string must be found at the start of a line. */
{
- int index;
+ int local_index;
char *temp;
int substring_okay = 0;
@@ -844,17 +941,20 @@ get_history_event (string, caller_index, delimiting_quote)
i++;
}
- for (index = i; string[i]; i++)
+ for (local_index = i; string[i]; i++)
if (whitespace (string[i]) ||
string[i] == '\n' ||
string[i] == ':' ||
(substring_okay && string[i] == '?') ||
+#if defined (SHELL)
+ member (string[i], ";&()|<>") ||
+#endif /* SHELL */
string[i] == delimiting_quote)
break;
- temp = (char *)alloca (1 + (i - index));
- strncpy (temp, &string[index], (i - index));
- temp[i - index] = '\0';
+ temp = (char *)alloca (1 + (i - local_index));
+ strncpy (temp, &string[local_index], (i - local_index));
+ temp[i - local_index] = '\0';
if (string[i] == '?')
i++;
@@ -863,19 +963,18 @@ get_history_event (string, caller_index, delimiting_quote)
search_again:
- index = history_search_internal
+ local_index = history_search_internal
(temp, -1, substring_okay ? NON_ANCHORED_SEARCH : ANCHORED_SEARCH);
- if (index < 0)
+ if (local_index < 0)
search_lost:
{
history_offset = history_length;
return ((char *)NULL);
}
- if (index == 0)
+ if (local_index == 0 || substring_okay)
{
- search_won:
entry = current_history ();
history_offset = history_length;
@@ -900,6 +999,28 @@ get_history_event (string, caller_index, delimiting_quote)
}
}
+#if defined (SHELL)
+/* Function for extracting single-quoted strings. Used for inhibiting
+ history expansion within single quotes. */
+
+/* Extract the contents of STRING as if it is enclosed in single quotes.
+ SINDEX, when passed in, is the offset of the character immediately
+ following the opening single quote; on exit, SINDEX is left pointing
+ to the closing single quote. */
+static void
+rl_string_extract_single_quoted (string, sindex)
+ char *string;
+ int *sindex;
+{
+ register int i = *sindex;
+
+ while (string[i] && string[i] != '\'')
+ i++;
+
+ *sindex = i;
+}
+#endif /* SHELL */
+
/* Expand the string STRING, placing the result into OUTPUT, a pointer
to a string. Returns:
@@ -922,8 +1043,6 @@ history_expand (string, output)
char *word_spec, *event;
int starting_index, only_printing = 0, substitute_globally = 0;
- char *get_history_word_specifier (), *rindex ();
-
/* The output string, and its length. */
int len = 0;
char *result = (char *)NULL;
@@ -932,7 +1051,7 @@ history_expand (string, output)
char *temp, tt[2], tbl[3];
/* Prepare the buffer for printing error messages. */
- result = (char *)xmalloc (len = 255);
+ result = (char *)xmalloc (len = 256);
result[0] = tt[1] = tbl[2] = '\0';
tbl[0] = '\\';
@@ -964,11 +1083,37 @@ history_expand (string, output)
/* `!' followed by one of the characters in history_no_expand_chars
is NOT an expansion. */
for (i = 0; string[i]; i++)
- if (string[i] == history_expansion_char)
- if (!string[i + 1] || member (string[i + 1], history_no_expand_chars))
- continue;
- else
- goto grovel;
+ {
+ if (string[i] == history_expansion_char)
+ {
+ if (!string[i + 1] || member (string[i + 1], history_no_expand_chars))
+ continue;
+#if defined (SHELL)
+ /* The shell uses ! as a pattern negation character in globbing [...]
+ expressions, so let those pass without expansion. */
+ else if (i > 0 && (string[i - 1] == '[') && member (']', string + i))
+ continue;
+#endif /* SHELL */
+ else
+ goto grovel;
+ }
+#if defined (SHELL)
+ else if (string[i] == '\'')
+ {
+ /* If this is bash, single quotes inhibit history expansion. */
+ i++;
+ rl_string_extract_single_quoted (string, &i);
+ }
+ else if (string[i] == '\\')
+ {
+ /* If this is bash, allow backslashes to quote single quotes and
+ the history expansion character. */
+ if (string[i + 1] == '\'' || (string[i + 1] == history_expansion_char))
+ i++;
+ }
+#endif /* SHELL */
+ }
+
free (result);
*output = savestring (string);
@@ -978,10 +1123,18 @@ history_expand (string, output)
for (i = j = 0; i < l; i++)
{
+ int passc = 0;
int tchar = string[i];
+
if (tchar == history_expansion_char)
tchar = -3;
+ if (passc)
+ {
+ passc = 0;
+ goto add_char;
+ }
+
switch (tchar)
{
case '\\':
@@ -992,7 +1145,27 @@ history_expand (string, output)
goto do_add;
}
else
- goto add_char;
+ {
+ passc++;
+ goto add_char;
+ }
+
+#if defined (SHELL)
+ case '\'':
+ {
+ /* If this is bash, single quotes inhibit history expansion. */
+ int quote = i, slen;
+
+ ++i;
+ rl_string_extract_single_quoted (string, &i);
+
+ slen = i - quote + 2;
+ temp = (char *)alloca (slen);
+ strncpy (temp, string + quote, slen);
+ temp[slen - 1] = '\0';
+ goto do_add;
+ }
+#endif /* SHELL */
/* case history_expansion_char: */
case -3:
@@ -1041,14 +1214,13 @@ history_expand (string, output)
if (!event)
event_not_found:
{
- int l = 1 + (i - starting_index);
+ int ll = 1 + (i - starting_index);
- temp = (char *)alloca (1 + l);
- strncpy (temp, string + starting_index, l);
- temp[l - 1] = 0;
+ temp = (char *)alloca (1 + ll);
+ strncpy (temp, string + starting_index, ll);
+ temp[ll - 1] = 0;
sprintf (result, "%s: %s.", temp,
word_spec_error ? "Bad word specifier" : "Event not found");
- error_exit:
*output = result;
return (-1);
}
@@ -1061,12 +1233,11 @@ history_expand (string, output)
/* There is no such thing as a `malformed word specifier'. However,
it is possible for a specifier that has no match. In that case,
we complain. */
- if (word_spec == (char *)-1)
- bad_word_spec:
- {
- word_spec_error++;
- goto event_not_found;
- }
+ if (word_spec == (char *)&error_pointer)
+ {
+ word_spec_error++;
+ goto event_not_found;
+ }
/* If no word specifier, than the thing of interest was the event. */
if (!word_spec)
@@ -1097,28 +1268,28 @@ history_expand (string, output)
/* :t discards all but the last part of the pathname. */
case 't':
- tstr = rindex (temp, '/');
+ tstr = strrchr (temp, '/');
if (tstr)
temp = ++tstr;
goto next_special;
/* :h discards the last part of a pathname. */
case 'h':
- tstr = rindex (temp, '/');
+ tstr = strrchr (temp, '/');
if (tstr)
*tstr = '\0';
goto next_special;
/* :r discards the suffix. */
case 'r':
- tstr = rindex (temp, '.');
+ tstr = strrchr (temp, '.');
if (tstr)
*tstr = '\0';
goto next_special;
/* :e discards everything but the suffix. */
case 'e':
- tstr = rindex (temp, '.');
+ tstr = strrchr (temp, '.');
if (tstr)
temp = tstr;
goto next_special;
@@ -1126,12 +1297,19 @@ history_expand (string, output)
/* :s/this/that substitutes `this' for `that'. */
/* :gs/this/that substitutes `this' for `that' globally. */
case 'g':
+#ifdef NOTYET
+ /* :g/this/that is equivalent to :gs/this/that */
+ substitute_globally = 1;
+ if (string[i + 2] == 's')
+ i++;
+#else
if (string[i + 2] == 's')
{
i++;
substitute_globally = 1;
goto substitute;
}
+#endif
else
case 's':
@@ -1141,7 +1319,7 @@ history_expand (string, output)
int delimiter = 0;
int si, l_this, l_that, l_temp = strlen (temp);
- if (i + 2 < strlen (string))
+ if (i + 2 < (int)strlen (string))
delimiter = string[i + 2];
if (!delimiter)
@@ -1246,8 +1424,8 @@ history_expand (string, output)
do_add:
j += strlen (temp);
- while (j > len)
- result = (char *)xrealloc (result, (len += 255));
+ while (j > (len - 1))
+ result = (char *)xrealloc (result, (len += 256));
strcpy (result + (j - strlen (temp)), temp);
}
@@ -1265,11 +1443,11 @@ history_expand (string, output)
}
/* Return a consed string which is the word specified in SPEC, and found
- in FROM. NULL is returned if there is no spec. -1 is returned if
- the word specified cannot be found. CALLER_INDEX is the offset in
- SPEC to start looking; it is updated to point to just after the last
- character parsed. */
-char *
+ in FROM. NULL is returned if there is no spec. The address of
+ ERROR_POINTER is returned if the word specified cannot be found.
+ CALLER_INDEX is the offset in SPEC to start looking; it is updated
+ to point to just after the last character parsed. */
+static char *
get_history_word_specifier (spec, from, caller_index)
char *spec, *from;
int *caller_index;
@@ -1327,7 +1505,6 @@ get_history_word_specifier (spec, from, caller_index)
goto get_last;
}
- get_first:
if (digit (spec[i]) && expecting_word_spec)
{
sscanf (spec + i, "%d", &first);
@@ -1376,7 +1553,7 @@ get_history_word_specifier (spec, from, caller_index)
if (result)
return (result);
else
- return ((char *)-1);
+ return ((char *)&error_pointer);
}
}
@@ -1470,38 +1647,40 @@ history_tokenize (string)
if (!string[i] || string[i] == history_comment_char)
return (result);
- if (member (string[i], "()\n")) {
- i++;
- goto got_token;
- }
+ if (member (string[i], "()\n"))
+ {
+ i++;
+ goto got_token;
+ }
- if (member (string[i], "<>;&|")) {
- int peek = string[i + 1];
+ if (member (string[i], "<>;&|$"))
+ {
+ int peek = string[i + 1];
- if (peek == string[i]) {
- if (peek == '<') {
- if (string[1 + 2] == '-')
+ if (peek == string[i] && peek != '$')
+ {
+ if (peek == '<' && string[i + 2] == '-')
+ i++;
+ i += 2;
+ goto got_token;
+ }
+ else
+ {
+ if ((peek == '&' &&
+ (string[i] == '>' || string[i] == '<')) ||
+ ((peek == '>') && (string[i] == '&')) ||
+ ((peek == '(') && (string[i] == '$')))
+ {
+ i += 2;
+ goto got_token;
+ }
+ }
+ if (string[i] != '$')
+ {
i++;
- i += 2;
- goto got_token;
- }
-
- if (member (peek, ">:&|")) {
- i += 2;
- goto got_token;
- }
- } else {
- if ((peek == '&' &&
- (string[i] == '>' || string[i] == '<')) ||
- ((peek == '>') &&
- (string[i] == '&'))) {
- i += 2;
- goto got_token;
- }
+ goto got_token;
+ }
}
- i++;
- goto got_token;
- }
/* Get word from string + i; */
{
@@ -1510,46 +1689,53 @@ history_tokenize (string)
if (member (string[i], "\"'`"))
delimiter = string[i++];
- for (;string[i]; i++) {
-
- if (string[i] == '\\') {
-
- if (string[i + 1] == '\n') {
- i++;
- continue;
- } else {
- if (delimiter != '\'')
- if ((delimiter != '"') ||
- (member (string[i], slashify_in_quotes))) {
- i++;
- continue;
- }
- }
- }
+ for (;string[i]; i++)
+ {
+ if (string[i] == '\\')
+ {
+ if (string[i + 1] == '\n')
+ {
+ i++;
+ continue;
+ }
+ else
+ {
+ if (delimiter != '\'')
+ if ((delimiter != '"') ||
+ (member (string[i], slashify_in_quotes)))
+ {
+ i++;
+ continue;
+ }
+ }
+ }
- if (delimiter && string[i] == delimiter) {
- delimiter = 0;
- continue;
- }
+ if (delimiter && string[i] == delimiter)
+ {
+ delimiter = 0;
+ continue;
+ }
- if (!delimiter && (member (string[i], " \t\n;&()|<>")))
- goto got_token;
+ if (!delimiter && (member (string[i], " \t\n;&()|<>")))
+ goto got_token;
- if (!delimiter && member (string[i], "\"'`")) {
- delimiter = string[i];
- continue;
+ if (!delimiter && member (string[i], "\"'`"))
+ {
+ delimiter = string[i];
+ continue;
+ }
}
- }
got_token:
len = i - start;
- if (result_index + 2 >= size) {
- if (!size)
- result = (char **)xmalloc ((size = 10) * (sizeof (char *)));
- else
- result =
- (char **)xrealloc (result, ((size += 10) * (sizeof (char *))));
- }
+ if (result_index + 2 >= size)
+ {
+ if (!size)
+ result = (char **)xmalloc ((size = 10) * (sizeof (char *)));
+ else
+ result =
+ (char **)xrealloc (result, ((size += 10) * (sizeof (char *))));
+ }
result[result_index] = (char *)xmalloc (1 + len);
strncpy (result[result_index], string + start, len);
result[result_index][len] = '\0';
@@ -1608,7 +1794,6 @@ memory_error_and_abort ()
abort ();
}
#endif /* STATIC_MALLOC */
-
/* **************************************************************** */
/* */
@@ -1684,7 +1869,7 @@ main ()
}
}
-#endif /* TEST */
+#endif /* TEST */
/*
* Local variables: