1/* History.c -- standalone history library */
2
3/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
4
5   This file contains the GNU History Library (the Library), a set of
6   routines for managing the text of previously typed lines.
7
8   The Library is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   The Library is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   The GNU General Public License is often shipped with GNU software, and
19   is generally kept in a file called COPYING or LICENSE.  If you do not
20   have a copy of the license, write to the Free Software Foundation,
21   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22
23/* The goal is to make the implementation transparent, so that you
24   don't have to know what data types are used, just what functions
25   you can call.  I think I have done that. */
26#define READLINE_LIBRARY
27
28#if defined (HAVE_CONFIG_H)
29#  include <config.h>
30#endif
31
32#include <stdio.h>
33
34#if defined (HAVE_STDLIB_H)
35#  include <stdlib.h>
36#else
37#  include "ansi_stdlib.h"
38#endif /* HAVE_STDLIB_H */
39
40#if defined (HAVE_UNISTD_H)
41#  ifdef _MINIX
42#    include <sys/types.h>
43#  endif
44#  include <unistd.h>
45#endif
46
47#include "history.h"
48#include "histlib.h"
49
50#include "xmalloc.h"
51
52/* The number of slots to increase the_history by. */
53#define DEFAULT_HISTORY_GROW_SIZE 50
54
55/* **************************************************************** */
56/*								    */
57/*			History Functions			    */
58/*								    */
59/* **************************************************************** */
60
61/* An array of HIST_ENTRY.  This is where we store the history. */
62static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
63
64/* Non-zero means that we have enforced a limit on the amount of
65   history that we save. */
66static int history_stifled;
67
68/* The current number of slots allocated to the input_history. */
69static int history_size;
70
71/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
72   entries to remember. */
73int history_max_entries;
74int max_input_history;	/* backwards compatibility */
75
76/* The current location of the interactive history pointer.  Just makes
77   life easier for outside callers. */
78int history_offset;
79
80/* The number of strings currently stored in the history list. */
81int history_length;
82
83/* The logical `base' of the history array.  It defaults to 1. */
84int history_base = 1;
85
86/* Return the current HISTORY_STATE of the history. */
87HISTORY_STATE *
88history_get_history_state ()
89{
90  HISTORY_STATE *state;
91
92  state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
93  state->entries = the_history;
94  state->offset = history_offset;
95  state->length = history_length;
96  state->size = history_size;
97  state->flags = 0;
98  if (history_stifled)
99    state->flags |= HS_STIFLED;
100
101  return (state);
102}
103
104/* Set the state of the current history array to STATE. */
105void
106history_set_history_state (state)
107     HISTORY_STATE *state;
108{
109  the_history = state->entries;
110  history_offset = state->offset;
111  history_length = state->length;
112  history_size = state->size;
113  if (state->flags & HS_STIFLED)
114    history_stifled = 1;
115}
116
117/* Begin a session in which the history functions might be used.  This
118   initializes interactive variables. */
119void
120using_history ()
121{
122  history_offset = history_length;
123}
124
125/* Return the number of bytes that the primary history entries are using.
126   This just adds up the lengths of the_history->lines. */
127int
128history_total_bytes ()
129{
130  register int i, result;
131
132  for (i = result = 0; the_history && the_history[i]; i++)
133    result += strlen (the_history[i]->line);
134
135  return (result);
136}
137
138/* Returns the magic number which says what history element we are
139   looking at now.  In this implementation, it returns history_offset. */
140int
141where_history ()
142{
143  return (history_offset);
144}
145
146/* Make the current history item be the one at POS, an absolute index.
147   Returns zero if POS is out of range, else non-zero. */
148int
149history_set_pos (pos)
150     int pos;
151{
152  if (pos > history_length || pos < 0 || !the_history)
153    return (0);
154  history_offset = pos;
155  return (1);
156}
157
158/* Return the current history array.  The caller has to be carefull, since this
159   is the actual array of data, and could be bashed or made corrupt easily.
160   The array is terminated with a NULL pointer. */
161HIST_ENTRY **
162history_list ()
163{
164  return (the_history);
165}
166
167/* Return the history entry at the current position, as determined by
168   history_offset.  If there is no entry there, return a NULL pointer. */
169HIST_ENTRY *
170current_history ()
171{
172  return ((history_offset == history_length) || the_history == 0)
173		? (HIST_ENTRY *)NULL
174		: the_history[history_offset];
175}
176
177/* Back up history_offset to the previous history entry, and return
178   a pointer to that entry.  If there is no previous entry then return
179   a NULL pointer. */
180HIST_ENTRY *
181previous_history ()
182{
183  return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
184}
185
186/* Move history_offset forward to the next history entry, and return
187   a pointer to that entry.  If there is no next entry then return a
188   NULL pointer. */
189HIST_ENTRY *
190next_history ()
191{
192  return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
193}
194
195/* Return the history entry which is logically at OFFSET in the history array.
196   OFFSET is relative to history_base. */
197HIST_ENTRY *
198history_get (offset)
199     int offset;
200{
201  int local_index;
202
203  local_index = offset - history_base;
204  return (local_index >= history_length || local_index < 0 || !the_history)
205		? (HIST_ENTRY *)NULL
206		: the_history[local_index];
207}
208
209/* Place STRING at the end of the history list.  The data field
210   is  set to NULL. */
211void
212add_history (string)
213     const char *string;
214{
215  HIST_ENTRY *temp;
216
217  if (history_stifled && (history_length == history_max_entries))
218    {
219      register int i;
220
221      /* If the history is stifled, and history_length is zero,
222	 and it equals history_max_entries, we don't save items. */
223      if (history_length == 0)
224	return;
225
226      /* If there is something in the slot, then remove it. */
227      if (the_history[0])
228	{
229	  free (the_history[0]->line);
230	  free (the_history[0]);
231	}
232
233      /* Copy the rest of the entries, moving down one slot. */
234      for (i = 0; i < history_length; i++)
235	the_history[i] = the_history[i + 1];
236
237      history_base++;
238    }
239  else
240    {
241      if (history_size == 0)
242	{
243	  history_size = DEFAULT_HISTORY_GROW_SIZE;
244	  the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
245	  history_length = 1;
246	}
247      else
248	{
249	  if (history_length == (history_size - 1))
250	    {
251	      history_size += DEFAULT_HISTORY_GROW_SIZE;
252	      the_history = (HIST_ENTRY **)
253		xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
254	    }
255	  history_length++;
256	}
257    }
258
259  temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
260  temp->line = savestring (string);
261  temp->data = (char *)NULL;
262
263  the_history[history_length] = (HIST_ENTRY *)NULL;
264  the_history[history_length - 1] = temp;
265}
266
267/* Make the history entry at WHICH have LINE and DATA.  This returns
268   the old entry so you can dispose of the data.  In the case of an
269   invalid WHICH, a NULL pointer is returned. */
270HIST_ENTRY *
271replace_history_entry (which, line, data)
272     int which;
273     const char *line;
274     histdata_t data;
275{
276  HIST_ENTRY *temp, *old_value;
277
278  if (which >= history_length)
279    return ((HIST_ENTRY *)NULL);
280
281  temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
282  old_value = the_history[which];
283
284  temp->line = savestring (line);
285  temp->data = data;
286  the_history[which] = temp;
287
288  return (old_value);
289}
290
291/* Remove history element WHICH from the history.  The removed
292   element is returned to you so you can free the line, data,
293   and containing structure. */
294HIST_ENTRY *
295remove_history (which)
296     int which;
297{
298  HIST_ENTRY *return_value;
299  register int i;
300
301  if (which >= history_length || !history_length)
302    return_value = (HIST_ENTRY *)NULL;
303  else
304    {
305      return_value = the_history[which];
306
307      for (i = which; i < history_length; i++)
308	the_history[i] = the_history[i + 1];
309
310      history_length--;
311    }
312
313  return (return_value);
314}
315
316/* Stifle the history list, remembering only MAX number of lines. */
317void
318stifle_history (max)
319     int max;
320{
321  register int i, j;
322
323  if (max < 0)
324    max = 0;
325
326  if (history_length > max)
327    {
328      /* This loses because we cannot free the data. */
329      for (i = 0, j = history_length - max; i < j; i++)
330	{
331	  free (the_history[i]->line);
332	  free (the_history[i]);
333	}
334
335      history_base = i;
336      for (j = 0, i = history_length - max; j < max; i++, j++)
337	the_history[j] = the_history[i];
338      the_history[j] = (HIST_ENTRY *)NULL;
339      history_length = j;
340    }
341
342  history_stifled = 1;
343  max_input_history = history_max_entries = max;
344}
345
346/* Stop stifling the history.  This returns the previous maximum
347   number of history entries.  The value is positive if the history
348   was stifled,  negative if it wasn't. */
349int
350unstifle_history ()
351{
352  if (history_stifled)
353    {
354      history_stifled = 0;
355      return (history_max_entries);
356    }
357  else
358    return (-history_max_entries);
359}
360
361int
362history_is_stifled ()
363{
364  return (history_stifled);
365}
366
367void
368clear_history ()
369{
370  register int i;
371
372  /* This loses because we cannot free the data. */
373  for (i = 0; i < history_length; i++)
374    {
375      free (the_history[i]->line);
376      free (the_history[i]);
377      the_history[i] = (HIST_ENTRY *)NULL;
378    }
379
380  history_offset = history_length = 0;
381}
382