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