1/* history.c -- standalone history library */
2
3/* Copyright (C) 1989-2005 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
55static char *hist_inittime PARAMS((void));
56
57/* **************************************************************** */
58/*								    */
59/*			History Functions			    */
60/*								    */
61/* **************************************************************** */
62
63/* An array of HIST_ENTRY.  This is where we store the history. */
64static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
65
66/* Non-zero means that we have enforced a limit on the amount of
67   history that we save. */
68static int history_stifled;
69
70/* The current number of slots allocated to the input_history. */
71static int history_size;
72
73/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
74   entries to remember. */
75int history_max_entries;
76int max_input_history;	/* backwards compatibility */
77
78/* The current location of the interactive history pointer.  Just makes
79   life easier for outside callers. */
80int history_offset;
81
82/* The number of strings currently stored in the history list. */
83int history_length;
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 and the associated
129   timestamps. */
130int
131history_total_bytes ()
132{
133  register int i, result;
134
135  for (i = result = 0; the_history && the_history[i]; i++)
136    result += HISTENT_BYTES (the_history[i]);
137
138  return (result);
139}
140
141/* Returns the magic number which says what history element we are
142   looking at now.  In this implementation, it returns history_offset. */
143int
144where_history ()
145{
146  return (history_offset);
147}
148
149/* Make the current history item be the one at POS, an absolute index.
150   Returns zero if POS is out of range, else non-zero. */
151int
152history_set_pos (pos)
153     int pos;
154{
155  if (pos > history_length || pos < 0 || !the_history)
156    return (0);
157  history_offset = pos;
158  return (1);
159}
160
161/* Return the current history array.  The caller has to be carefull, since this
162   is the actual array of data, and could be bashed or made corrupt easily.
163   The array is terminated with a NULL pointer. */
164HIST_ENTRY **
165history_list ()
166{
167  return (the_history);
168}
169
170/* Return the history entry at the current position, as determined by
171   history_offset.  If there is no entry there, return a NULL pointer. */
172HIST_ENTRY *
173current_history ()
174{
175  return ((history_offset == history_length) || the_history == 0)
176		? (HIST_ENTRY *)NULL
177		: the_history[history_offset];
178}
179
180/* Back up history_offset to the previous history entry, and return
181   a pointer to that entry.  If there is no previous entry then return
182   a NULL pointer. */
183HIST_ENTRY *
184previous_history ()
185{
186  return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
187}
188
189/* Move history_offset forward to the next history entry, and return
190   a pointer to that entry.  If there is no next entry then return a
191   NULL pointer. */
192HIST_ENTRY *
193next_history ()
194{
195  return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
196}
197
198/* Return the history entry which is logically at OFFSET in the history array.
199   OFFSET is relative to history_base. */
200HIST_ENTRY *
201history_get (offset)
202     int offset;
203{
204  int local_index;
205
206  local_index = offset - history_base;
207  return (local_index >= history_length || local_index < 0 || the_history == 0)
208		? (HIST_ENTRY *)NULL
209		: the_history[local_index];
210}
211
212HIST_ENTRY *
213alloc_history_entry (string, ts)
214     char *string;
215     char *ts;
216{
217  HIST_ENTRY *temp;
218
219  temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
220
221  temp->line = string ? savestring (string) : string;
222  temp->data = (char *)NULL;
223  temp->timestamp = ts;
224
225  return temp;
226}
227
228time_t
229history_get_time (hist)
230     HIST_ENTRY *hist;
231{
232  char *ts;
233  time_t t;
234
235  if (hist == 0 || hist->timestamp == 0)
236    return 0;
237  ts = hist->timestamp;
238  if (ts[0] != history_comment_char)
239    return 0;
240  t = (time_t) atol (ts + 1);		/* XXX - should use strtol() here */
241  return t;
242}
243
244static char *
245hist_inittime ()
246{
247  time_t t;
248  char ts[64], *ret;
249
250  t = (time_t) time ((time_t *)0);
251#if defined (HAVE_VSNPRINTF)		/* assume snprintf if vsnprintf exists */
252  snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t);
253#else
254  sprintf (ts, "X%lu", (unsigned long) t);
255#endif
256  ret = savestring (ts);
257  ret[0] = history_comment_char;
258
259  return ret;
260}
261
262/* Place STRING at the end of the history list.  The data field
263   is  set to NULL. */
264void
265add_history (string)
266     const char *string;
267{
268  HIST_ENTRY *temp;
269
270  if (history_stifled && (history_length == history_max_entries))
271    {
272      register int i;
273
274      /* If the history is stifled, and history_length is zero,
275	 and it equals history_max_entries, we don't save items. */
276      if (history_length == 0)
277	return;
278
279      /* If there is something in the slot, then remove it. */
280      if (the_history[0])
281	(void) free_history_entry (the_history[0]);
282
283      /* Copy the rest of the entries, moving down one slot. */
284      for (i = 0; i < history_length; i++)
285	the_history[i] = the_history[i + 1];
286
287      history_base++;
288    }
289  else
290    {
291      if (history_size == 0)
292	{
293	  history_size = DEFAULT_HISTORY_GROW_SIZE;
294	  the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
295	  history_length = 1;
296	}
297      else
298	{
299	  if (history_length == (history_size - 1))
300	    {
301	      history_size += DEFAULT_HISTORY_GROW_SIZE;
302	      the_history = (HIST_ENTRY **)
303		xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
304	    }
305	  history_length++;
306	}
307    }
308
309  temp = alloc_history_entry (string, hist_inittime ());
310
311  the_history[history_length] = (HIST_ENTRY *)NULL;
312  the_history[history_length - 1] = temp;
313}
314
315/* Change the time stamp of the most recent history entry to STRING. */
316void
317add_history_time (string)
318     const char *string;
319{
320  HIST_ENTRY *hs;
321
322  hs = the_history[history_length - 1];
323  FREE (hs->timestamp);
324  hs->timestamp = savestring (string);
325}
326
327/* Free HIST and return the data so the calling application can free it
328   if necessary and desired. */
329histdata_t
330free_history_entry (hist)
331     HIST_ENTRY *hist;
332{
333  histdata_t x;
334
335  if (hist == 0)
336    return ((histdata_t) 0);
337  FREE (hist->line);
338  FREE (hist->timestamp);
339  x = hist->data;
340  free (hist);
341  return (x);
342}
343
344HIST_ENTRY *
345copy_history_entry (hist)
346     HIST_ENTRY *hist;
347{
348  HIST_ENTRY *ret;
349  char *ts;
350
351  if (hist == 0)
352    return hist;
353
354  ret = alloc_history_entry (hist->line, (char *)NULL);
355
356  ts = hist->timestamp ? savestring (hist->timestamp) : hist->timestamp;
357  ret->timestamp = ts;
358
359  ret->data = hist->data;
360
361  return ret;
362}
363
364/* Make the history entry at WHICH have LINE and DATA.  This returns
365   the old entry so you can dispose of the data.  In the case of an
366   invalid WHICH, a NULL pointer is returned. */
367HIST_ENTRY *
368replace_history_entry (which, line, data)
369     int which;
370     const char *line;
371     histdata_t data;
372{
373  HIST_ENTRY *temp, *old_value;
374
375  if (which < 0 || which >= history_length)
376    return ((HIST_ENTRY *)NULL);
377
378  temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
379  old_value = the_history[which];
380
381  temp->line = savestring (line);
382  temp->data = data;
383  temp->timestamp = savestring (old_value->timestamp);
384  the_history[which] = temp;
385
386  return (old_value);
387}
388
389/* Replace the DATA in the specified history entries, replacing OLD with
390   NEW.  WHICH says which one(s) to replace:  WHICH == -1 means to replace
391   all of the history entries where entry->data == OLD; WHICH == -2 means
392   to replace the `newest' history entry where entry->data == OLD; and
393   WHICH >= 0 means to replace that particular history entry's data, as
394   long as it matches OLD. */
395void
396replace_history_data (which,old, new)
397     int which;
398     histdata_t *old, *new;
399{
400  HIST_ENTRY *entry;
401  register int i, last;
402
403  if (which < -2 || which >= history_length || history_length == 0 || the_history == 0)
404    return;
405
406  if (which >= 0)
407    {
408      entry = the_history[which];
409      if (entry && entry->data == old)
410	entry->data = new;
411      return;
412    }
413
414  last = -1;
415  for (i = 0; i < history_length; i++)
416    {
417      entry = the_history[i];
418      if (entry == 0)
419	continue;
420      if (entry->data == old)
421	{
422	  last = i;
423	  if (which == -1)
424	    entry->data = new;
425	}
426    }
427  if (which == -2 && last >= 0)
428    {
429      entry = the_history[last];
430      entry->data = new;	/* XXX - we don't check entry->old */
431    }
432}
433
434/* Remove history element WHICH from the history.  The removed
435   element is returned to you so you can free the line, data,
436   and containing structure. */
437HIST_ENTRY *
438remove_history (which)
439     int which;
440{
441  HIST_ENTRY *return_value;
442  register int i;
443
444  if (which < 0 || which >= history_length || history_length ==  0 || the_history == 0)
445    return ((HIST_ENTRY *)NULL);
446
447  return_value = the_history[which];
448
449  for (i = which; i < history_length; i++)
450    the_history[i] = the_history[i + 1];
451
452  history_length--;
453
454  return (return_value);
455}
456
457/* Stifle the history list, remembering only MAX number of lines. */
458void
459stifle_history (max)
460     int max;
461{
462  register int i, j;
463
464  if (max < 0)
465    max = 0;
466
467  if (history_length > max)
468    {
469      /* This loses because we cannot free the data. */
470      for (i = 0, j = history_length - max; i < j; i++)
471	free_history_entry (the_history[i]);
472
473      history_base = i;
474      for (j = 0, i = history_length - max; j < max; i++, j++)
475	the_history[j] = the_history[i];
476      the_history[j] = (HIST_ENTRY *)NULL;
477      history_length = j;
478    }
479
480  history_stifled = 1;
481  max_input_history = history_max_entries = max;
482}
483
484/* Stop stifling the history.  This returns the previous maximum
485   number of history entries.  The value is positive if the history
486   was stifled,  negative if it wasn't. */
487int
488unstifle_history ()
489{
490  if (history_stifled)
491    {
492      history_stifled = 0;
493      return (history_max_entries);
494    }
495  else
496    return (-history_max_entries);
497}
498
499int
500history_is_stifled ()
501{
502  return (history_stifled);
503}
504
505void
506clear_history ()
507{
508  register int i;
509
510  /* This loses because we cannot free the data. */
511  for (i = 0; i < history_length; i++)
512    {
513      free_history_entry (the_history[i]);
514      the_history[i] = (HIST_ENTRY *)NULL;
515    }
516
517  history_offset = history_length = 0;
518}
519