aboutsummaryrefslogtreecommitdiff
path: root/readline/history.c
diff options
context:
space:
mode:
authorStu Grossman <grossman@cygnus>1991-11-19 05:59:18 +0000
committerStu Grossman <grossman@cygnus>1991-11-19 05:59:18 +0000
commit870ca2534097fc727b6762fab958fad76722d638 (patch)
tree45e293360e93ebd8320410c8b9b65fb6729f13ff /readline/history.c
parentc5bbc6ea4136d242ea345285f0758826d019dbaf (diff)
downloadgdb-870ca2534097fc727b6762fab958fad76722d638.zip
gdb-870ca2534097fc727b6762fab958fad76722d638.tar.gz
gdb-870ca2534097fc727b6762fab958fad76722d638.tar.bz2
Integrate new readline from Brian Fox.
Diffstat (limited to 'readline/history.c')
-rw-r--r--readline/history.c415
1 files changed, 310 insertions, 105 deletions
diff --git a/readline/history.c b/readline/history.c
index 3c07d11..9f0a41e 100644
--- a/readline/history.c
+++ b/readline/history.c
@@ -25,24 +25,27 @@
you can call. I think I have done that. */
/* Remove these declarations when we have a complete libgnu.a. */
-#define STATIC_MALLOC
-#ifndef STATIC_MALLOC
+#if !defined (STATIC_MALLOC)
extern char *xmalloc (), *xrealloc ();
#else
static char *xmalloc (), *xrealloc ();
#endif
#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <fcntl.h>
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else
-#if defined (sparc) && defined (sun)
-#include <alloca.h>
+#if defined (__GNUC__)
+# define alloca __builtin_alloca
#else
+# if defined (sparc) || defined (HAVE_ALLOCA_H)
+# include <alloca.h>
+# else
extern char *alloca ();
-#endif
-#endif
+# endif /* sparc || HAVE_ALLOCA_H */
+#endif /* !__GNU_C__ */
#include "history.h"
@@ -64,7 +67,7 @@ extern char *alloca ();
/* **************************************************************** */
/* */
-/* History functions */
+/* History Functions */
/* */
/* **************************************************************** */
@@ -73,18 +76,18 @@ static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
/* Non-zero means that we have enforced a limit on the amount of
history that we save. */
-static int history_stifled = 0;
+int history_stifled = 0;
/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
entries to remember. */
-static int max_input_history;
+int max_input_history;
/* The current location of the interactive history pointer. Just makes
life easier for outside callers. */
static int history_offset = 0;
/* The number of strings currently stored in the input_history list. */
-static int history_length = 0;
+int history_length = 0;
/* The current number of slots allocated to the input_history. */
static int history_size = 0;
@@ -121,6 +124,21 @@ using_history ()
history_offset = history_length;
}
+/* Return the number of bytes that the primary history entries are using.
+ This just adds up the lengths of the_history->lines. */
+int
+history_total_bytes ()
+{
+ register int i, result;
+
+ result = 0;
+
+ for (i = 0; the_history && the_history[i]; i++)
+ result += strlen (the_history[i]->line);
+
+ return (result);
+}
+
/* Place STRING at the end of the history list. The data field
is set to NULL. */
void
@@ -129,43 +147,50 @@ add_history (string)
{
HIST_ENTRY *temp;
- if (history_stifled && (history_length == max_input_history)) {
- register int i;
-
- /* If the history is stifled, and history_length is zero,
- and it equals max_input_history, we don't save items. */
- if (!history_length)
- return;
+ if (history_stifled && (history_length == max_input_history))
+ {
+ register int i;
- /* If there is something in the slot, then remove it. */
- if (the_history[0]) {
- free (the_history[0]->line);
- free (the_history[0]);
- }
+ /* If the history is stifled, and history_length is zero,
+ and it equals max_input_history, we don't save items. */
+ if (!history_length)
+ return;
- for (i = 0; i < history_length; i++)
- the_history[i] = the_history[i + 1];
+ /* If there is something in the slot, then remove it. */
+ if (the_history[0])
+ {
+ free (the_history[0]->line);
+ free (the_history[0]);
+ }
- history_base++;
+ for (i = 0; i < history_length; i++)
+ the_history[i] = the_history[i + 1];
- } else {
+ history_base++;
- if (!history_size) {
- the_history =
- (HIST_ENTRY **)xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE)
- * sizeof (HIST_ENTRY *));
- history_length = 1;
+ }
+ else
+ {
+ if (!history_size)
+ {
+ the_history = (HIST_ENTRY **)
+ xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE)
+ * sizeof (HIST_ENTRY *));
+ history_length = 1;
- } else {
- if (history_length == (history_size - 1)) {
- the_history =
- (HIST_ENTRY **)xrealloc (the_history,
- ((history_size += DEFAULT_HISTORY_GROW_SIZE)
- * sizeof (HIST_ENTRY *)));
- }
- history_length++;
+ }
+ else
+ {
+ if (history_length == (history_size - 1))
+ {
+ the_history = (HIST_ENTRY **)
+ xrealloc (the_history,
+ ((history_size += DEFAULT_HISTORY_GROW_SIZE)
+ * sizeof (HIST_ENTRY *)));
+ }
+ history_length++;
+ }
}
- }
temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
temp->line = savestring (string);
@@ -208,15 +233,22 @@ where_history ()
}
/* Search the history for STRING, starting at history_offset.
- If DIRECTION < 0, then the search is through previous entries,
- else through subsequent. If the string is found, then
- current_history () is the history entry, and the value of this function
- is the offset in the line of that history entry that the string was
- found in. Otherwise, nothing is changed, and a -1 is returned. */
-int
-history_search (string, direction)
+ If DIRECTION < 0, then the search is through previous entries, else
+ through subsequent. If ANCHORED is non-zero, the string must
+ appear at the beginning of a history line, otherwise, the string
+ may appear anywhere in the line. If the string is found, then
+ current_history () is the history entry, and the value of this
+ function is the offset in the line of that history entry that the
+ string was found in. Otherwise, nothing is changed, and a -1 is
+ returned. */
+
+#define ANCHORED_SEARCH 1
+#define NON_ANCHORED_SEARCH 0
+
+static int
+history_search_internal (string, direction, anchored)
char *string;
- int direction;
+ int direction, anchored;
{
register int i = history_offset;
register int reverse = (direction < 0);
@@ -248,7 +280,19 @@ history_search (string, direction)
if (string_len > index)
goto next_line;
- /* Do the actual search. */
+ /* Handle anchored searches first. */
+ if (anchored == ANCHORED_SEARCH)
+ {
+ if (strncmp (string, line, string_len) == 0)
+ {
+ history_offset = i;
+ return (0);
+ }
+
+ goto next_line;
+ }
+
+ /* Do substring search. */
if (reverse)
{
index -= string_len;
@@ -265,7 +309,7 @@ history_search (string, direction)
}
else
{
- register int limit = (string_len - index) + 1;
+ register int limit = index - string_len + 1;
index = 0;
while (index < limit)
@@ -286,6 +330,24 @@ history_search (string, direction)
}
}
+/* Do a non-anchored search for STRING through the history in DIRECTION. */
+int
+history_search (string, direction)
+ char *string;
+ int direction;
+{
+ return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
+}
+
+/* Do an anchored search for string through the history in DIRECTION. */
+int
+history_search_prefix (string, direction)
+ char *string;
+ int direction;
+{
+ return (history_search_internal (string, direction, ANCHORED_SEARCH));
+}
+
/* Remove history element WHICH from the history. The removed
element is returned to you so you can free the line, data,
and containing structure. */
@@ -307,6 +369,7 @@ remove_history (which)
history_length--;
}
+
return (return_value);
}
@@ -364,16 +427,11 @@ history_filename (filename)
char *home = (char *)getenv ("HOME");
if (!home) home = ".";
return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history"));
- strcpy (return_val, home);
- strcat (return_val, "/");
- strcat (return_val, ".history");
+ sprintf (return_val, "%s/.history", home);
}
return (return_val);
}
-/* What to use until the line gets too big. */
-#define TYPICAL_LINE_SIZE 2048
-
/* Add the contents of FILENAME to the history list, a line at a time.
If FILENAME is NULL, then read from ~/.history. Returns 0 if
successful, or errno if not. */
@@ -381,64 +439,206 @@ int
read_history (filename)
char *filename;
{
- char *input = history_filename (filename);
- FILE *file = fopen (input, "r");
- char *line = (char *)xmalloc (TYPICAL_LINE_SIZE);
- int line_size = TYPICAL_LINE_SIZE;
- int done = 0;
+ return (read_history_range (filename, 0, -1));
+}
- if (!file)
+/* Read a range of lines from FILENAME, adding them to the history list.
+ Start reading at the FROM'th line and end at the TO'th. If FROM
+ is zero, start at the beginning. If TO is less than FROM, read
+ until the end of the file. If FILENAME is NULL, then read from
+ ~/.history. Returns 0 if successful, or errno if not. */
+int
+read_history_range (filename, from, to)
+ char *filename;
+ int from, to;
+{
+ register int line_start, line_end;
+ 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);
+
+ if ((file < 0) ||
+ (stat (input, &finfo) == -1))
+ goto error_and_exit;
+
+ buffer = (char *)xmalloc (finfo.st_size + 1);
+
+ if (read (file, buffer, finfo.st_size) != finfo.st_size)
+ error_and_exit:
{
- extern int errno;
- free (line);
+ if (file >= 0)
+ close (file);
+
+ if (buffer)
+ free (buffer);
+
return (errno);
}
- while (!done)
- {
- int c;
- int i;
+ close (file);
- i = 0;
- while (!(done = ((c = getc (file)) == EOF)))
- {
- if (c == '\n')
- break;
+ /* Set TO to larger than end of file if negative. */
+ if (to < 0)
+ to = finfo.st_size;
- line [i++] = c;
- if (i == line_size)
- line = (char *)xrealloc (line, line_size += TYPICAL_LINE_SIZE);
- }
- line[i] = '\0';
- if (line[0])
- add_history (line);
+ /* Start at beginning of file, work to end. */
+ line_start = line_end = current_line = 0;
+
+ /* Skip lines until we are at FROM. */
+ while (line_start < finfo.st_size && current_line < from)
+ {
+ for (line_end = line_start; line_end < finfo.st_size; line_end++)
+ if (buffer[line_end] == '\n')
+ {
+ current_line++;
+ line_start = line_end + 1;
+ if (current_line == from)
+ break;
+ }
}
- free (line);
- fclose (file);
+
+ /* If there are lines left to gobble, then gobble them now. */
+ for (line_end = line_start; line_end < finfo.st_size; line_end++)
+ if (buffer[line_end] == '\n')
+ {
+ buffer[line_end] = '\0';
+
+ if (buffer[line_start])
+ add_history (buffer + line_start);
+
+ current_line++;
+
+ if (current_line >= to)
+ break;
+
+ line_start = line_end + 1;
+ }
return (0);
}
-/* Overwrite FILENAME with the current history. If FILENAME is NULL,
- then write the history list to ~/.history. Values returned
- are as in read_history ().*/
-int
-write_history (filename)
+/* Truncate the history file FNAME, leaving only LINES trailing lines.
+ If FNAME is NULL, then use ~/.history. */
+history_truncate_file (fname, lines)
+ char *fname;
+ register int lines;
+{
+ register int i;
+ int file;
+ char *buffer = (char *)NULL, *filename;
+ struct stat finfo;
+
+ filename = history_filename (fname);
+ if (stat (filename, &finfo) == -1)
+ goto truncate_exit;
+
+ file = open (filename, O_RDONLY, 0666);
+
+ if (file == -1)
+ goto truncate_exit;
+
+ buffer = (char *)xmalloc (finfo.st_size + 1);
+ read (file, buffer, finfo.st_size);
+ close (file);
+
+ /* Count backwards from the end of buffer until we have passed
+ LINES lines. */
+ for (i = finfo.st_size; lines && i; i--)
+ {
+ if (buffer[i] == '\n')
+ lines--;
+ }
+
+ /* If there are fewer lines in the file than we want to truncate to,
+ then we are all done. */
+ if (!i)
+ goto truncate_exit;
+
+ /* Otherwise, write from the start of this line until the end of the
+ buffer. */
+ for (--i; i; i--)
+ if (buffer[i] == '\n')
+ {
+ i++;
+ break;
+ }
+
+ file = open (filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if (file == -1)
+ goto truncate_exit;
+
+ write (file, buffer + i, finfo.st_size - i);
+ close (file);
+
+ truncate_exit:
+ if (buffer)
+ free (buffer);
+
+ free (filename);
+}
+
+#define HISTORY_APPEND 0
+#define HISTORY_OVERWRITE 1
+
+/* Workhorse function for writing history. Writes NELEMENT entries
+ from the history list to FILENAME. OVERWRITE is non-zero if you
+ wish to replace FILENAME with the entries. */
+static int
+history_do_write (filename, nelements, overwrite)
char *filename;
+ int nelements, overwrite;
{
extern int errno;
- char *output = history_filename (filename);
- FILE *file = fopen (output, "w");
register int i;
+ char *output = history_filename (filename);
+ int file, mode;
+ char cr = '\n';
+
+ if (overwrite)
+ mode = O_WRONLY | O_CREAT | O_TRUNC;
+ else
+ mode = O_WRONLY | O_APPEND;
+
+ if ((file = open (output, mode, 0666)) == -1)
+ return (errno);
- if (!file) return (errno);
- if (!history_length) return (0);
+ if (nelements > history_length)
+ nelements = history_length;
- for (i = 0; i < history_length; i++)
- fprintf (file, "%s\n", the_history[i]->line);
+ for (i = history_length - nelements; i < history_length; i++)
+ {
+ if (write (file, the_history[i]->line, strlen (the_history[i]->line)) < 0)
+ break;
+ if (write (file, &cr, 1) < 0)
+ break;
+ }
- fclose (file);
+ close (file);
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
+append_history (nelements, filename)
+ int nelements;
+ char *filename;
+{
+ return (history_do_write (filename, nelements, HISTORY_APPEND));
+}
+
+/* Overwrite FILENAME with the current history. If FILENAME is NULL,
+ then write the history list to ~/.history. Values returned
+ are as in read_history ().*/
+int
+write_history (filename)
+ char *filename;
+{
+ return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
+}
/* Return the history entry at the current position, as determined by
history_offset. If there is no entry there, return a NULL pointer. */
@@ -653,7 +853,8 @@ get_history_event (string, caller_index, delimiting_quote)
search_again:
- index = history_search (temp, -1);
+ index = history_search_internal
+ (temp, -1, substring_okay ? NON_ANCHORED_SEARCH : ANCHORED_SEARCH);
if (index < 0)
search_lost:
@@ -662,9 +863,7 @@ get_history_event (string, caller_index, delimiting_quote)
return ((char *)NULL);
}
- if (index == 0 || substring_okay ||
- (strncmp (temp, the_history[history_offset]->line,
- strlen (temp)) == 0))
+ if (index == 0)
{
search_won:
entry = current_history ();
@@ -1174,7 +1373,7 @@ get_history_word_specifier (spec, from, caller_index)
/* Extract the args specified, starting at FIRST, and ending at LAST.
The args are taken from STRING. If either FIRST or LAST is < 0,
then make that arg count from the right (subtract from the number of
- tokens, so that FIRST = -1 means the next to last token on the line. */
+ tokens, so that FIRST = -1 means the next to last token on the line). */
char *
history_arg_extract (first, last, string)
int first, last;
@@ -1205,7 +1404,7 @@ history_arg_extract (first, last, string)
last++;
- if (first > len || last > len)
+ if (first > len || last > len || first < 0 || last < 0)
result = ((char *)NULL);
else
{
@@ -1353,7 +1552,7 @@ history_tokenize (string)
return (result);
}
-#ifdef STATIC_MALLOC
+#if defined (STATIC_MALLOC)
/* **************************************************************** */
/* */
@@ -1379,10 +1578,16 @@ xrealloc (pointer, bytes)
char *pointer;
int bytes;
{
- char *temp = (char *)realloc (pointer, bytes);
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)xmalloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
if (!temp)
memory_error_and_abort ();
+
return (temp);
}