xref: /openbsd-src/gnu/lib/libreadline/history.c (revision 9704b281e65e1189747652d0ba55eee892cff5f7)
11acd27e7Smillert /* History.c -- standalone history library */
21acd27e7Smillert 
31acd27e7Smillert /* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
41acd27e7Smillert 
51acd27e7Smillert    This file contains the GNU History Library (the Library), a set of
61acd27e7Smillert    routines for managing the text of previously typed lines.
71acd27e7Smillert 
81acd27e7Smillert    The Library is free software; you can redistribute it and/or modify
91acd27e7Smillert    it under the terms of the GNU General Public License as published by
101acd27e7Smillert    the Free Software Foundation; either version 2, or (at your option)
111acd27e7Smillert    any later version.
121acd27e7Smillert 
131acd27e7Smillert    The Library is distributed in the hope that it will be useful, but
141acd27e7Smillert    WITHOUT ANY WARRANTY; without even the implied warranty of
151acd27e7Smillert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
161acd27e7Smillert    General Public License for more details.
171acd27e7Smillert 
181acd27e7Smillert    The GNU General Public License is often shipped with GNU software, and
191acd27e7Smillert    is generally kept in a file called COPYING or LICENSE.  If you do not
201acd27e7Smillert    have a copy of the license, write to the Free Software Foundation,
211acd27e7Smillert    59 Temple Place, Suite 330, Boston, MA 02111 USA. */
221acd27e7Smillert 
231acd27e7Smillert /* The goal is to make the implementation transparent, so that you
241acd27e7Smillert    don't have to know what data types are used, just what functions
251acd27e7Smillert    you can call.  I think I have done that. */
261acd27e7Smillert #define READLINE_LIBRARY
271acd27e7Smillert 
281acd27e7Smillert #if defined (HAVE_CONFIG_H)
291acd27e7Smillert #  include <config.h>
301acd27e7Smillert #endif
311acd27e7Smillert 
321acd27e7Smillert #include <stdio.h>
331acd27e7Smillert 
341acd27e7Smillert #if defined (HAVE_STDLIB_H)
351acd27e7Smillert #  include <stdlib.h>
361acd27e7Smillert #else
371acd27e7Smillert #  include "ansi_stdlib.h"
381acd27e7Smillert #endif /* HAVE_STDLIB_H */
391acd27e7Smillert 
401acd27e7Smillert #if defined (HAVE_UNISTD_H)
411acd27e7Smillert #  ifdef _MINIX
421acd27e7Smillert #    include <sys/types.h>
431acd27e7Smillert #  endif
441acd27e7Smillert #  include <unistd.h>
451acd27e7Smillert #endif
461acd27e7Smillert 
471acd27e7Smillert #include "history.h"
481acd27e7Smillert #include "histlib.h"
491acd27e7Smillert 
501acd27e7Smillert #include "xmalloc.h"
511acd27e7Smillert 
521acd27e7Smillert /* The number of slots to increase the_history by. */
531acd27e7Smillert #define DEFAULT_HISTORY_GROW_SIZE 50
541acd27e7Smillert 
551acd27e7Smillert /* **************************************************************** */
561acd27e7Smillert /*								    */
571acd27e7Smillert /*			History Functions			    */
581acd27e7Smillert /*								    */
591acd27e7Smillert /* **************************************************************** */
601acd27e7Smillert 
611acd27e7Smillert /* An array of HIST_ENTRY.  This is where we store the history. */
621acd27e7Smillert static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
631acd27e7Smillert 
641acd27e7Smillert /* Non-zero means that we have enforced a limit on the amount of
651acd27e7Smillert    history that we save. */
661acd27e7Smillert static int history_stifled;
671acd27e7Smillert 
68*15b117eaSkettenis /* The current number of slots allocated to the input_history. */
69*15b117eaSkettenis static int history_size;
70*15b117eaSkettenis 
711acd27e7Smillert /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
721acd27e7Smillert    entries to remember. */
73*15b117eaSkettenis int history_max_entries;
74*15b117eaSkettenis int max_input_history;	/* backwards compatibility */
751acd27e7Smillert 
761acd27e7Smillert /* The current location of the interactive history pointer.  Just makes
771acd27e7Smillert    life easier for outside callers. */
781acd27e7Smillert int history_offset;
791acd27e7Smillert 
801acd27e7Smillert /* The number of strings currently stored in the history list. */
811acd27e7Smillert int history_length;
821acd27e7Smillert 
831acd27e7Smillert /* The logical `base' of the history array.  It defaults to 1. */
841acd27e7Smillert int history_base = 1;
851acd27e7Smillert 
861acd27e7Smillert /* Return the current HISTORY_STATE of the history. */
871acd27e7Smillert HISTORY_STATE *
history_get_history_state()881acd27e7Smillert history_get_history_state ()
891acd27e7Smillert {
901acd27e7Smillert   HISTORY_STATE *state;
911acd27e7Smillert 
921acd27e7Smillert   state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
931acd27e7Smillert   state->entries = the_history;
941acd27e7Smillert   state->offset = history_offset;
951acd27e7Smillert   state->length = history_length;
961acd27e7Smillert   state->size = history_size;
971acd27e7Smillert   state->flags = 0;
981acd27e7Smillert   if (history_stifled)
991acd27e7Smillert     state->flags |= HS_STIFLED;
1001acd27e7Smillert 
1011acd27e7Smillert   return (state);
1021acd27e7Smillert }
1031acd27e7Smillert 
1041acd27e7Smillert /* Set the state of the current history array to STATE. */
1051acd27e7Smillert void
history_set_history_state(state)1061acd27e7Smillert history_set_history_state (state)
1071acd27e7Smillert      HISTORY_STATE *state;
1081acd27e7Smillert {
1091acd27e7Smillert   the_history = state->entries;
1101acd27e7Smillert   history_offset = state->offset;
1111acd27e7Smillert   history_length = state->length;
1121acd27e7Smillert   history_size = state->size;
1131acd27e7Smillert   if (state->flags & HS_STIFLED)
1141acd27e7Smillert     history_stifled = 1;
1151acd27e7Smillert }
1161acd27e7Smillert 
1171acd27e7Smillert /* Begin a session in which the history functions might be used.  This
1181acd27e7Smillert    initializes interactive variables. */
1191acd27e7Smillert void
using_history()1201acd27e7Smillert using_history ()
1211acd27e7Smillert {
1221acd27e7Smillert   history_offset = history_length;
1231acd27e7Smillert }
1241acd27e7Smillert 
1251acd27e7Smillert /* Return the number of bytes that the primary history entries are using.
1261acd27e7Smillert    This just adds up the lengths of the_history->lines. */
1271acd27e7Smillert int
history_total_bytes()1281acd27e7Smillert history_total_bytes ()
1291acd27e7Smillert {
1301acd27e7Smillert   register int i, result;
1311acd27e7Smillert 
132*15b117eaSkettenis   for (i = result = 0; the_history && the_history[i]; i++)
1331acd27e7Smillert     result += strlen (the_history[i]->line);
1341acd27e7Smillert 
1351acd27e7Smillert   return (result);
1361acd27e7Smillert }
1371acd27e7Smillert 
1381acd27e7Smillert /* Returns the magic number which says what history element we are
1391acd27e7Smillert    looking at now.  In this implementation, it returns history_offset. */
1401acd27e7Smillert int
where_history()1411acd27e7Smillert where_history ()
1421acd27e7Smillert {
1431acd27e7Smillert   return (history_offset);
1441acd27e7Smillert }
1451acd27e7Smillert 
1461acd27e7Smillert /* Make the current history item be the one at POS, an absolute index.
1471acd27e7Smillert    Returns zero if POS is out of range, else non-zero. */
1481acd27e7Smillert int
history_set_pos(pos)1491acd27e7Smillert history_set_pos (pos)
1501acd27e7Smillert      int pos;
1511acd27e7Smillert {
1521acd27e7Smillert   if (pos > history_length || pos < 0 || !the_history)
1531acd27e7Smillert     return (0);
1541acd27e7Smillert   history_offset = pos;
1551acd27e7Smillert   return (1);
1561acd27e7Smillert }
1571acd27e7Smillert 
1581acd27e7Smillert /* Return the current history array.  The caller has to be carefull, since this
1591acd27e7Smillert    is the actual array of data, and could be bashed or made corrupt easily.
1601acd27e7Smillert    The array is terminated with a NULL pointer. */
1611acd27e7Smillert HIST_ENTRY **
history_list()1621acd27e7Smillert history_list ()
1631acd27e7Smillert {
1641acd27e7Smillert   return (the_history);
1651acd27e7Smillert }
1661acd27e7Smillert 
1671acd27e7Smillert /* Return the history entry at the current position, as determined by
1681acd27e7Smillert    history_offset.  If there is no entry there, return a NULL pointer. */
1691acd27e7Smillert HIST_ENTRY *
current_history()1701acd27e7Smillert current_history ()
1711acd27e7Smillert {
1721acd27e7Smillert   return ((history_offset == history_length) || the_history == 0)
1731acd27e7Smillert 		? (HIST_ENTRY *)NULL
1741acd27e7Smillert 		: the_history[history_offset];
1751acd27e7Smillert }
1761acd27e7Smillert 
1771acd27e7Smillert /* Back up history_offset to the previous history entry, and return
1781acd27e7Smillert    a pointer to that entry.  If there is no previous entry then return
1791acd27e7Smillert    a NULL pointer. */
1801acd27e7Smillert HIST_ENTRY *
previous_history()1811acd27e7Smillert previous_history ()
1821acd27e7Smillert {
1831acd27e7Smillert   return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
1841acd27e7Smillert }
1851acd27e7Smillert 
1861acd27e7Smillert /* Move history_offset forward to the next history entry, and return
1871acd27e7Smillert    a pointer to that entry.  If there is no next entry then return a
1881acd27e7Smillert    NULL pointer. */
1891acd27e7Smillert HIST_ENTRY *
next_history()1901acd27e7Smillert next_history ()
1911acd27e7Smillert {
1921acd27e7Smillert   return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
1931acd27e7Smillert }
1941acd27e7Smillert 
1951acd27e7Smillert /* Return the history entry which is logically at OFFSET in the history array.
1961acd27e7Smillert    OFFSET is relative to history_base. */
1971acd27e7Smillert HIST_ENTRY *
history_get(offset)1981acd27e7Smillert history_get (offset)
1991acd27e7Smillert      int offset;
2001acd27e7Smillert {
2011acd27e7Smillert   int local_index;
2021acd27e7Smillert 
2031acd27e7Smillert   local_index = offset - history_base;
2041acd27e7Smillert   return (local_index >= history_length || local_index < 0 || !the_history)
2051acd27e7Smillert 		? (HIST_ENTRY *)NULL
2061acd27e7Smillert 		: the_history[local_index];
2071acd27e7Smillert }
2081acd27e7Smillert 
2091acd27e7Smillert /* Place STRING at the end of the history list.  The data field
2101acd27e7Smillert    is  set to NULL. */
2111acd27e7Smillert void
add_history(string)2121acd27e7Smillert add_history (string)
213*15b117eaSkettenis      const char *string;
2141acd27e7Smillert {
2151acd27e7Smillert   HIST_ENTRY *temp;
2161acd27e7Smillert 
217*15b117eaSkettenis   if (history_stifled && (history_length == history_max_entries))
2181acd27e7Smillert     {
2191acd27e7Smillert       register int i;
2201acd27e7Smillert 
2211acd27e7Smillert       /* If the history is stifled, and history_length is zero,
222*15b117eaSkettenis 	 and it equals history_max_entries, we don't save items. */
2231acd27e7Smillert       if (history_length == 0)
2241acd27e7Smillert 	return;
2251acd27e7Smillert 
2261acd27e7Smillert       /* If there is something in the slot, then remove it. */
2271acd27e7Smillert       if (the_history[0])
2281acd27e7Smillert 	{
2291acd27e7Smillert 	  free (the_history[0]->line);
2301acd27e7Smillert 	  free (the_history[0]);
2311acd27e7Smillert 	}
2321acd27e7Smillert 
2331acd27e7Smillert       /* Copy the rest of the entries, moving down one slot. */
2341acd27e7Smillert       for (i = 0; i < history_length; i++)
2351acd27e7Smillert 	the_history[i] = the_history[i + 1];
2361acd27e7Smillert 
2371acd27e7Smillert       history_base++;
2381acd27e7Smillert     }
2391acd27e7Smillert   else
2401acd27e7Smillert     {
2411acd27e7Smillert       if (history_size == 0)
2421acd27e7Smillert 	{
2431acd27e7Smillert 	  history_size = DEFAULT_HISTORY_GROW_SIZE;
2441acd27e7Smillert 	  the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
2451acd27e7Smillert 	  history_length = 1;
2461acd27e7Smillert 	}
2471acd27e7Smillert       else
2481acd27e7Smillert 	{
2491acd27e7Smillert 	  if (history_length == (history_size - 1))
2501acd27e7Smillert 	    {
2511acd27e7Smillert 	      history_size += DEFAULT_HISTORY_GROW_SIZE;
2521acd27e7Smillert 	      the_history = (HIST_ENTRY **)
2531acd27e7Smillert 		xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
2541acd27e7Smillert 	    }
2551acd27e7Smillert 	  history_length++;
2561acd27e7Smillert 	}
2571acd27e7Smillert     }
2581acd27e7Smillert 
2591acd27e7Smillert   temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
2601acd27e7Smillert   temp->line = savestring (string);
2611acd27e7Smillert   temp->data = (char *)NULL;
2621acd27e7Smillert 
2631acd27e7Smillert   the_history[history_length] = (HIST_ENTRY *)NULL;
2641acd27e7Smillert   the_history[history_length - 1] = temp;
2651acd27e7Smillert }
2661acd27e7Smillert 
2671acd27e7Smillert /* Make the history entry at WHICH have LINE and DATA.  This returns
2681acd27e7Smillert    the old entry so you can dispose of the data.  In the case of an
2691acd27e7Smillert    invalid WHICH, a NULL pointer is returned. */
2701acd27e7Smillert HIST_ENTRY *
replace_history_entry(which,line,data)2711acd27e7Smillert replace_history_entry (which, line, data)
2721acd27e7Smillert      int which;
273*15b117eaSkettenis      const char *line;
2741acd27e7Smillert      histdata_t data;
2751acd27e7Smillert {
276*15b117eaSkettenis   HIST_ENTRY *temp, *old_value;
2771acd27e7Smillert 
2781acd27e7Smillert   if (which >= history_length)
2791acd27e7Smillert     return ((HIST_ENTRY *)NULL);
2801acd27e7Smillert 
281*15b117eaSkettenis   temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
2821acd27e7Smillert   old_value = the_history[which];
2831acd27e7Smillert 
2841acd27e7Smillert   temp->line = savestring (line);
2851acd27e7Smillert   temp->data = data;
2861acd27e7Smillert   the_history[which] = temp;
2871acd27e7Smillert 
2881acd27e7Smillert   return (old_value);
2891acd27e7Smillert }
2901acd27e7Smillert 
2911acd27e7Smillert /* Remove history element WHICH from the history.  The removed
2921acd27e7Smillert    element is returned to you so you can free the line, data,
2931acd27e7Smillert    and containing structure. */
2941acd27e7Smillert HIST_ENTRY *
remove_history(which)2951acd27e7Smillert remove_history (which)
2961acd27e7Smillert      int which;
2971acd27e7Smillert {
2981acd27e7Smillert   HIST_ENTRY *return_value;
299*15b117eaSkettenis   register int i;
3001acd27e7Smillert 
3011acd27e7Smillert   if (which >= history_length || !history_length)
3021acd27e7Smillert     return_value = (HIST_ENTRY *)NULL;
3031acd27e7Smillert   else
3041acd27e7Smillert     {
3051acd27e7Smillert       return_value = the_history[which];
3061acd27e7Smillert 
3071acd27e7Smillert       for (i = which; i < history_length; i++)
3081acd27e7Smillert 	the_history[i] = the_history[i + 1];
3091acd27e7Smillert 
3101acd27e7Smillert       history_length--;
3111acd27e7Smillert     }
3121acd27e7Smillert 
3131acd27e7Smillert   return (return_value);
3141acd27e7Smillert }
3151acd27e7Smillert 
3161acd27e7Smillert /* Stifle the history list, remembering only MAX number of lines. */
3171acd27e7Smillert void
stifle_history(max)3181acd27e7Smillert stifle_history (max)
3191acd27e7Smillert      int max;
3201acd27e7Smillert {
321*15b117eaSkettenis   register int i, j;
322*15b117eaSkettenis 
3231acd27e7Smillert   if (max < 0)
3241acd27e7Smillert     max = 0;
3251acd27e7Smillert 
3261acd27e7Smillert   if (history_length > max)
3271acd27e7Smillert     {
3281acd27e7Smillert       /* This loses because we cannot free the data. */
3291acd27e7Smillert       for (i = 0, j = history_length - max; i < j; i++)
3301acd27e7Smillert 	{
3311acd27e7Smillert 	  free (the_history[i]->line);
3321acd27e7Smillert 	  free (the_history[i]);
3331acd27e7Smillert 	}
3341acd27e7Smillert 
3351acd27e7Smillert       history_base = i;
3361acd27e7Smillert       for (j = 0, i = history_length - max; j < max; i++, j++)
3371acd27e7Smillert 	the_history[j] = the_history[i];
3381acd27e7Smillert       the_history[j] = (HIST_ENTRY *)NULL;
3391acd27e7Smillert       history_length = j;
3401acd27e7Smillert     }
3411acd27e7Smillert 
3421acd27e7Smillert   history_stifled = 1;
343*15b117eaSkettenis   max_input_history = history_max_entries = max;
3441acd27e7Smillert }
3451acd27e7Smillert 
346*15b117eaSkettenis /* Stop stifling the history.  This returns the previous maximum
347*15b117eaSkettenis    number of history entries.  The value is positive if the history
348*15b117eaSkettenis    was stifled,  negative if it wasn't. */
3491acd27e7Smillert int
unstifle_history()3501acd27e7Smillert unstifle_history ()
3511acd27e7Smillert {
3521acd27e7Smillert   if (history_stifled)
3531acd27e7Smillert     {
3541acd27e7Smillert       history_stifled = 0;
355*15b117eaSkettenis       return (history_max_entries);
3561acd27e7Smillert     }
357*15b117eaSkettenis   else
358*15b117eaSkettenis     return (-history_max_entries);
3591acd27e7Smillert }
3601acd27e7Smillert 
3611acd27e7Smillert int
history_is_stifled()3621acd27e7Smillert history_is_stifled ()
3631acd27e7Smillert {
3641acd27e7Smillert   return (history_stifled);
3651acd27e7Smillert }
3661acd27e7Smillert 
3671acd27e7Smillert void
clear_history()3681acd27e7Smillert clear_history ()
3691acd27e7Smillert {
3701acd27e7Smillert   register int i;
3711acd27e7Smillert 
3721acd27e7Smillert   /* This loses because we cannot free the data. */
3731acd27e7Smillert   for (i = 0; i < history_length; i++)
3741acd27e7Smillert     {
3751acd27e7Smillert       free (the_history[i]->line);
3761acd27e7Smillert       free (the_history[i]);
3771acd27e7Smillert       the_history[i] = (HIST_ENTRY *)NULL;
3781acd27e7Smillert     }
3791acd27e7Smillert 
3801acd27e7Smillert   history_offset = history_length = 0;
3811acd27e7Smillert }
382